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
toddnewmantoddnewman 

Incorrect error message? You have uncommitted work pending. - Part 2

Hi again.  I have discussed this problem previously.  Incidentally, I can't duplicate the problem in the same way anymore but that's not the important story for today.


Sadly, my full codebase (as opposed to the contrived class) was still throwing the same error...even after I made sure all the class versions were up in the 20s.  But after much tedious debugging I have found another problem.  And a spoiler...there are more problems to find.  I still get the error if I run my "real" code.  But this one is verifiable so I thought I'd share it now.


If you send an email too soon before you make a callout, you will get the "uncommitted work" error.  I often debug code by sending myself emails with state, especially messy code like this with future calls and such.  Unfortunately for me, if I'm having trouble with a callout, one thing I'm going to want to know is what arguments I am sending out!  So naturally I had emailing code right before my callout.


What I am finding is that if the email is near the callout in code (and presumably execution time) I get the error.  This contrived class is not long enough to really demonstrate it.  But if I had a couple hundred lines of code with some SELECT statements I could email out inside the future method context without error.  For this class I demonstrated by putting the "safe" email before the future call.

 

}

public with sharing class EmailBeforeCalloutIssue {

 

// alter the static vars and then run this line anonymous

//EmailBeforeCalloutIssue.makeItHappen();

 

    private static Boolean I_LIKE_SUCCESS = true;

    private static String EMAIL_ADDR = 'your_email_address__________';

 

    public static void makeItHappen() {

 

        Map<String, String> params = new Map<String, String>();

        EmailBeforeCalloutIssue.buildParams(params);

        String qs = makeStringFromMap(params);

 

        // ****** emailing HERE (far from .send) is not a problem

        if (EmailBeforeCalloutIssue.I_LIKE_SUCCESS) EmailBeforeCalloutIssue.sendDebugEmail('The Dude perseveres.');

 

        EmailBeforeCalloutIssue.makeItHappenCallout(qs);

 

    }

 

    @future(callout=true)

    public static void makeItHappenCallout(String qs) {

 

        // ****** emailing HERE (too close to .send) causes failure

        // it's possible to email successfuly after we've entered the future as long as there is sufficient delay such as database reads

        if (!EmailBeforeCalloutIssue.I_LIKE_SUCCESS) EmailBeforeCalloutIssue.sendDebugEmail('an occasional acid flashback...');

 

        Http h = new Http();

        HttpRequest req = new HttpRequest();

        req.setEndpoint('https://secure.future.stage.ariasystems.net/api/ws/api_ws_class_dispatcher.php');

        req.setMethod('POST');

        req.setBody(qs);

 

        String debugString = 'TTN: ';

        try {

            HttpResponse res = h.send(req);

            debugString = debugString + 'success! ' + res.getBody();

 

        } catch (Exception e) {

            debugString = debugString + 'error! ' + e.getMessage();

        }

 

        // tell me the result, I need to know!

        EmailBeforeCalloutIssue.sendDebugEmail(debugString);

 

    }

 

    public static void sendDebugEmail(String body) {

        Messaging.SingleEmailMessage mail2 = new Messaging.SingleEmailMessage();

        mail2.setToAddresses(new String[] {EmailBeforeCalloutIssue.EMAIL_ADDR});

        mail2.setCcAddresses(new String[] {});

        mail2.setReplyTo('noreply@salesforce.com');

        mail2.setSenderDisplayName('Salesforce');

        mail2.setSubject('Salesforce debug');

        mail2.setBccSender(false);

        mail2.setUseSignature(false);

        mail2.setPlainTextBody(body);

        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail2 });

    }

 

    private static void buildParams(Map<String, String> params) {

 

        EmailBeforeCalloutIssue.putParam(params, 'email', '');

        EmailBeforeCalloutIssue.putParam(params, 'city', 'Del Mar');

    // etc

 

    }

 

    private static String makeStringFromMap(Map<String, String> params) {

        String res = '';

        for (String key : params.keySet()) {

            res += key + '=' + EncodingUtil.urlEncode(params.get(key), 'UTF-8') + '&';

        }

 

        res = res.substring(0, res.length() - 1);

        return res;

    }

 

    public static void putParam(Map<String, String> params, String paramName, String paramValue) {

        if (paramValue != null) {

            params.put(paramName, paramValue);

        } else {

            params.put(paramName, '');

        }

    }

 

David@ClosedwonDavid@Closedwon

Todd,

 

I can confirm that this was the cause (and solution) for the uncommitted work error I was getting.  Since my particular callout runs in @future, I was using email alerts for monitoring and debugging.  Commenting those email routines out moved me past the uncommitted work error.

 

Thanks for posting this.

 

David