function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Ben Warner 54Ben Warner 54 

Can't access named credential from Apex code within a package in subscriber org

I have a package that contains apex code using a named credential to access an external REST service. The code works fine in the dev org, but once packaged and deployed to a test (subscriber) org I'm getting a System.CalloutException with the following message:
 
The callout couldn't access the endpoint. You might not have the required permissions, or the named credential "My_Named_Credential" might not exist.

The named credential is not included in the package as the endpoint configuration needs to be different for each org, however I've created the named credential in the test (subscriber) org, exactly as I have it in the dev org. The documentation on the use of named credentials in Apex code within packages suggests that this should work fine:

<excerpt>
If you package Apex code that specifies a named credential as a callout endpoint, also add the named credential to that package or otherwise make sure that the subscriber organization has a valid named credential with the same name.
</excerpt>

Ref: http://www.salesforce.com/us/developer/docs/packagingGuide/Content/packaging_component_behavior.htm

My Apex code:

            // Setup the REST call
            Http http = new Http();
            String endpointURL = 'callout:My_Named_Credential'; // Named Credential
    
            // Establish the request
            HttpRequest reqData = new HttpRequest();
            reqData.setTimeout(20000);
            reqData.setEndpoint(endpointURL);
            reqData.setMethod('POST');

            // Attempt the API callout
            HTTPResponse res = http.send(reqData);

Has anyone been able to successfully get this working? Are there any work-arounds I need to be aware of?

Thanks in advance,
BW.
 
Best Answer chosen by Ben Warner 54
Eric BowdenEric Bowden
Ben, I also had the same issue today.

Try to prefix the name of your named credential with ".__" as shown in the sample below.
req.setEndpoint('callout:.__My_Named_Credential/some_path');

I found this answer in the Salesforce Packaging Guide (https://help.salesforce.com/help/pdfs/en/salesforce_packaging_guide.pdf

Cheers,
Eric
 

All Answers

Ben Warner 54Ben Warner 54
I forgot to mention, I am logged in as administrator in the test org so permissions should not play into it.
Eric BowdenEric Bowden
Ben, I also had the same issue today.

Try to prefix the name of your named credential with ".__" as shown in the sample below.
req.setEndpoint('callout:.__My_Named_Credential/some_path');

I found this answer in the Salesforce Packaging Guide (https://help.salesforce.com/help/pdfs/en/salesforce_packaging_guide.pdf

Cheers,
Eric
 
This was selected as the best answer
Ben Warner 54Ben Warner 54
Hey Eric, thanks for the response.

This is the same advice I got from Salesforce support. One catch is that using the local namespace with the '.__' breaks the code in the developer org as there is no way to create a Named Credential outside the package namespace. So the only solution I could determine to resolve the issue in both dev org and subscriber org is to check the org Id to see if we were running in the dev org and remove the name space if we are, as below:
 
final String DEV_ORG_ID = <my_dev_org_Id>;
        String endpointURL = 'callout:.__My_Named_Credential'; // Named Credential on local namespace
        if(UserInfo.getOrganizationId() == DEV_ORG_ID){ // Developer org does not support local namespace
            endpointURL = 'callout:My_Named_Credential';
        }

Thanks again,
BW.
Sateesh BaluSateesh Balu
Thanks Eric Bowden 
Jheel D. AgrawalJheel D. Agrawal
Eric's Answer is correct itself. But I would like to add a few code items similar to Ben's Code for everyone's ease. This code will work even when working with Namespace Scratch Orgs.
You can simply use the following code:
request.setEndPoint('callout:.__Named_Credential_Name/some_path');
if(Utility.ORG_NAMESPACE == 'PackageNamespace') { request.setEndPoint('callout:Named_Credential_Name/some_path'); }
And here is the code of the Utility Class:
public with sharing class Utility 
{
    public static String ORG_NAMESPACE 
    {
        get
        {
            if(ORG_NAMESPACE == null)
            {
                return [SELECT NamespacePrefix FROM Organization].NamespacePrefix;
            }
            return ORG_NAMESPACE;
        }
        set;
    }
}
I hope this helps. And thanks a lot Eric for your answer it helped me a lot. 

Regards,
Jheel
Ben Clayton 23Ben Clayton 23
Thanks Jheel! This utility class was very helpful.