We have method EnrollmentUtil.createNewEnrollment which contains a http callout on create of custom object Enrolment__c, and a test class to test this method. I'm trying to figure out how this class was passing 2 months ago when it was deployed to production, but with no changes since then it is now failing in production and sandboxes. On running EnrollmentUtil_Test we're getting the "You have uncommitted work pending. Please commit or rollback before calling out" error on EnrollmentUtil line 57 when the http callout is being made.

Apex Class code snippet

public class EnrollmentUtil {

public static string response {get;set;}

public static boolean disableTrigger {get{if(disableTrigger == null) disableTrigger = false; return disableTrigger;} set;} 

public static void newEnrollment(map<Id,Enrolment__c> mapEnrollments) {
    if(Test.isRunningTest() && Limits.getFutureCalls() >= Limits.getLimitFutureCalls()) {
        system.debug(LoggingLevel.Error, 'Future method limit reached. Skipping...');
    } else {
        if(!Test.isRunningTest() && System.IsBatch() == false && System.isFuture() == false) {

public static void createNewEnrollment(set<Id> enrollmentIds) {
    System.debug(loggingLevel.Error, 'enrollmentIds==>' + enrollmentIds);
    list<Enrolment__c> listEnrollments = new list<Enrolment__c>([select Id, Opportunity__r.Account.Name, Opportunity__r.Account.Id, Opportunity__r.Account.PersonEmail, Opportunity__r.Related_Course__r.LMS_Code__c from Enrolment__c where Id in: enrollmentIds]);
    list<Account> listAccountUpdate = new list<Account>();
    for(Enrolment__c e: listEnrollments) {
        /* Step 1: Add the user if they don't already exist */

        //Callout to search for the user via email
        String userSearch = 'url string';
        Http h = new Http();

        HttpRequest req = new HttpRequest();

        HttpResponse res = h.send(req); // <---- Where "uncommitted work pending" error is thrown
        response = res.getBody();
                System.debug(loggingLevel.Error, '*** response: ' + response);

        // code to parse json and form list of accounts to update if user found

    //Update the account 
    update listAccountUpdate;

Test class:

private class EnrollmentUtil_Test {

static testMethod void testNewEnrollment(){ 
    RecordType rtSA = [Select Id from RecordType Where Name = 'Student Account'];

    Account acc = new Account();
    acc.FirstName = 'accFirst';
    acc.LastName = 'accLast';
    acc.RecordTypeId = rtSA.Id;
    acc.PersonEmail = '[email protected]';
    insert acc;

    RecordType rtCUA = [Select Id from RecordType Where Name = 'College/University Account'];

    Account acc1 = new Account();
    acc1.Name = 'AccName';
    acc1.RecordTypeId = rtCUA.Id;
    insert acc1; 

    Qualification__c qual = new Qualification__c();
    qual.Name = 'Test Qual';
    qual.LMS_Code__c = '1';
    qual.Account__c = acc1.Id;
    insert qual;

    Qualification_Unit__c u = new Qualification_Unit__c();
    u.Qualification__c = qual.Id;
    u.Name = 'UnitName';
    insert u;

    RecordType rtSO = [Select Id from RecordType Where Name = 'Student Opportunity'];
    Opportunity opp = new Opportunity();
    opp.Name = 'Test_Student_Opp';
    opp.AccountId = acc.Id;
    opp.RecordTypeId = rtSO.Id;
    opp.StageName = 'In Progress';
    opp.CloseDate = Date.today();
    opp.Related_Course__c = qual.Id;
    opp.Education_Provider_Account__c = acc1.Id;
    opp.CloseDate = date.today()+30;
    insert opp;   

    map<Id,Enrolment__c> mapId = new map<Id,Enrolment__c>();
    Enrolment__c en = new Enrolment__c();
    en.Opportunity__c = opp.Id;
    en.Account__c = acc.Id;
    en.Start_Date__c = Date.today();
    insert en;

    // This causes a fake response to be generated
    Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());

    // Call the method that invokes a callout


public class MockHttpResponseGenerator implements HttpCalloutMock {
    // Implement this interface method
    public HTTPResponse respond(HTTPRequest req) {

        // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type', 'application/json');
        return res;

As I said this was previously passing and no change that would impact this has been made since, except for Salesforce releases. The startTest and stopTest flags look to be placed correctly to separate DML statements from the callout, I can't see any DML statements prior to the callout in the method, and in sandbox I've tried removing the @future tag with no change. Could Winter 16 have broken this?

  • Stranger still, in a stripped-out dev environment where I've removed a bunch of workflows and fields but has this code and relevant metadata unchanged, the test is passing. Even if there are related workflows on the Enrollment object, the startTest and stopTest flags and lack of any DML in the code means they shouldn't have any impact on this right? Oct 30, 2015 at 3:05
  • Do you have any workflow email alerts that are new or running? If so, workflow email alerts cause the mock to break - See this question: salesforce.stackexchange.com/questions/71259/…
    – Eric
    Oct 30, 2015 at 4:04
  • 1
    is it something the method(CreateNewEnrollment) has any DML statements prior to calling the callout?
    – Goki
    Oct 30, 2015 at 4:14

1 Answer 1


Since you said in your comment that disabling workflows allows it to pass I am going to assume that some of those workflows are email alerts.

This is a know issue which I first reported back in April and now has a know issue associated with it that is unresolved.

Issue with Email Alerts and Test.setMock - Uncommitted Work Pending

Known Issue:


And I love the workaround:

Separate DML and Workflow (with email) in different transactions

how exactly do you do that?

What I did, I created a flag on the object that the test methods set and have all the workflows causing the issue evaluate to false if that flag was true. No reason to fire off an email in a test anyway. But that also meant I had to isolate the WFR Email alert from the other Field Updates that were in the same workflow. Not doing that could cause your asserts to fail.

  • Thanks so much for the response Eric, otherwise I would have spent the next several days tearing my hair out and the code apart trying to find a solution to a platform bug. There was indeed a workflow to send email off the same object, and once I disabled it the tests passed. I'll try your suggestion for controlling email send with a flag. Nov 1, 2015 at 22:13
  • @PhilipClark - Your welcome. Glad I could help. It was a tough one to initially nail down when I ran into it....
    – Eric
    Nov 1, 2015 at 22:49
  • According to Salesforce this was fixed in Winter '17 release patch. Today I had similar issue which turned out to be caused by process builder that was starting approval process.
    – neff
    Jan 25, 2017 at 20:27
  • @Eric, Thank you so much for your answer, i finally found the solution. Yes in my production org, i do have some WFR on object(Account and contact). i just deactivate it, and validating the change set in production is successful(before i got error on this). my quesion is, if i activate this WFR again (if client want it) after deployment , will it cause error? Jul 18, 2017 at 7:06
  • If it is true, how to separete the DML and WF in different transaction through Flag, can you explain it more clearly. Jul 18, 2017 at 7:08

You must log in to answer this question.

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