26

I have an APEX REST POST method that is being called from an external system 'A'.

Processing this POST I need to callout to another external system 'B' and based on its response continue with my application logic, eventually returning the result to system 'A'.

The problem is that I'm getting an Error: "System.CalloutException: Callout loop not allowed"

is there any way to get around this ?

5
  • 1
    Very interesting design, not sure what the business reason is but generally, in these cases, we do a Callout from System A directly to System B and if there is any data that you want to get from Salesforce you can do by APEX REST GET and then callout to System B (from System A only) Jan 11, 2013 at 15:09
  • 2
    Are you testing your rest method by making an httprequest from anonymous apex by any chance? the callout loop error only happens when you try and make a callout to another salesforce method from a "call-in". If you are calling out to an external system it should work. Jan 15, 2013 at 14:38
  • 1
    Here's a business reason: System A doesn't have credentials for System B, but the Salesforce instance does. System A authenticates with Salesforce, which then retrieves data from System B to supply to System A.
    – tomlogic
    Feb 1, 2013 at 22:48
  • 1
    workaround: if it were a mission critical one-off using systems you control, an HTTP proxy service (eg squid) could drop the Sfdc-Stack-Depth header before forwarding the requests ;-) Feb 1, 2013 at 23:04
  • 1
    I just ran into this problem myself. The feature that makes them unique is one SF org (a) is making a SOAP request to a different SF org (b). After the transaction is over, b has a future method that makes a SOAP call to an external (non-SF) system, (c). That's when I get the callout loop error.
    – tggagne
    May 11, 2016 at 19:33

5 Answers 5

19

No, there is not an immediate workaround to this :-(

The mechanism by which they measure that 'callout depth' is by transmitting an HTTP header on requests originating from Apex, Sfdc-Stack-Depth: 1 - if you try and trick the platform by explicitly setting this header to '' etc, you'll find the value is very sticky!

Unfortunately for us, there is a good business reason behind this "feature" on Salesforce' part. It is by design, to prevents callouts from blocking threads between multiple orgs / instances. sequence diagram

(hopefully this sequence diagram illustrates the intention; as an HTTP callout could take a while, the number of loopback connections is restricted to 1, otherwise imagine the DoS implications)

You might be able to overcome this issue if your B callout were read-only and its contents were updated infrequently.

You could schedule a batch process to regularly perform the callout and avail its response in a Document (or such). Then read that Document when responding to A, decoupling the two. But I admit that may be unlikely in your case...

2
  • 1
    Why won't an future solve this problem? I have a customer with five production orgs. Two of these orgs need to collaborate. Org A makes an future callout inside an AFTER INSERT trigger. When Org B sends Org A a SOAP message that results in triggering the future method, the future method fails with the callout exception.
    – tggagne
    May 12, 2016 at 17:23
  • Future is a good idea if you don't need the value returned synchronously @tggagne May 12, 2016 at 17:25
6

@user31's answer is absolutely incorrect (or I am misunderstanding the question). There is nothing preventing you from making callouts from Apex REST methods to external systems. Here is some sample code:

@RestResource(urlMapping='/restexample/')
global with sharing class RestExample 
{
    @HttpGet
    global static string doGet() 
    {
        HttpRequest req = new HttpRequest();

        req.setMethod('GET');
        req.setEndpoint('https://www.google.com');
        system.debug('request body: '+req.getbody());

        HTTPResponse res = new http().send(req);

        return res.getBody();
    }
}

Note that you cannot make callouts to Salesforce as that will give you the callout loop error.

You can test this code through curl or something similar. Testing it through anonymous Apex will give the callout loop error as you are making a callout from within Salesforce to Salesforce.

5
  • Ya got me there grigriforice; in my answer I've made the unstated assumption that System A or System B is a Salesforce system ;) hopefully Prafulla Patil can respond to your comment on the question itself to clarify this. Jan 15, 2013 at 23:00
  • @user320 yeah, that definitely might be the case but he called them both external systems. Didn't want anyone else to think this was impossible. Jan 15, 2013 at 23:23
  • 1
    I can confirm that a RESTful interface called from a Force.com site cannot make a web callout, and I'll likely have to modify my workflow to use an @future method for that callout. Thankfully, in my case, I don't need to respond with data from the callout.
    – tomlogic
    Feb 1, 2013 at 22:53
  • 3
    And I can now confirm that @future isn't enough to break the loop. I still get a CalloutException from my FutureHandler. I can see where Salesforce would want to avoid some runaway processes spawning connections between instances, but this is starting to make my life more difficult.
    – tomlogic
    Feb 1, 2013 at 23:19
  • As of today, I can't call an external service from an Apex REST resource. Maybe this is something that was changed with the latest Salesforce release? Sep 23, 2015 at 16:38
2

You can solve this by placing the second API call in an implements Queueable class. It doesn't work for @future.

1
  • 1
    Welcome to SFSE and thanks for the answer! This got auto-flagged as low quality - probably because of the length. Can you expand on it a little just to avoid any accidental removal because I think you do have a solution here.
    – Matt Lacey
    Oct 18, 2020 at 23:39
0

I've encountered this, but different scenario. I have a setup where we have two orgs connected via an integration tool. In addition to these two SF orgs, we are connected to an external service.

A - SF Org 1 B - SF Org 2 C - 3rd party service

B is connected to A & C directly. To save licensing costs if A wants to talk to C it must go through B.

This encounters the callout loop without a workaround.

What happens is on org B there is a service that runs and passes calls along in a new session.

Now the packages are managed, but here is what I know about how it works: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_interface_system_schedulablecontext.htm

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm

https://help.salesforce.com/articleView?id=000340086&type=1&mode=1 https://developer.salesforce.com/forums/?id=906F0000000g27DIAQ

0

I have the similar situation but simpler - external system A sends REST API request to create a record in Salesforce, trigger is executed on the object, future method is executed to make a callout to another external system B. This future method fails with the System.CalloutException: Callout loop not allowed error. The solution for me was to make this callout from Scheduled class. So instead of executing future method, I scheduled class to be executed in 2 seconds from current time.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .