+ Start a Discussion
Bill McBill Mc 

Exception in @future method: You have uncommitted work pending. Please commit or rollback before calling out

Hello. Currently when we approve Opportunities an Apex trigger creates custom Invoice objects with status = "Pending".

A trigger on this custom Invoice object checks for that status and if found makes a call to a future method (prefaced with "@future(callout=true)")  in another Apex class with the set of new Invoice objects.  This method then makes a callout to our external invoicing service for each of the new invoices.

The problem occurs at the start of each month when we approve approximately 50 new Opportunities. An exception is thrown at the point that the call to the external invoicing service: You have uncommitted work pending. Please commit or rollback before calling out.

My question is: why is this exception being raised when the callout is done within a method marked as @future?

Kind regards, Bill





 
Mudasir WaniMudasir Wani
Hi Bill,

I can see the similar post here but no solution 
https://developer.salesforce.com/forums/ForumsMain?id=906F000000096ibIAA

Just want to make a point.
Make your DML before your callout if you are not doing it as of now.
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_testing_dml.htm

Don't forget to select best answer to make our efforts visible in the developer forum.
Please mark this as solution by selecting it as best answer if this solves your problem, So that if anyone has this issue this post can help.
Amit Chaudhary 8Amit Chaudhary 8
Hi Bill,

Below point you need to consider for all Future call

1) Methods with the future annotation must be static methods
2) can only return a void type
3) The specified parameters must be primitive data types, arrays of primitive data types, or collections of primitive data types
4) Methods with the future annotation cannot take sObjects or objects as arguments.
5) You can invoke future methods the same way you invoke any other method. However, a future method can’t invoke another future method
6) No more than 50 method calls per Apex invocation
7) Asynchronous calls, such as @future or executeBatch, called in a startTest, stopTest block, do not count against your limits for the number of queued jobs
8) The maximum number of future method invocations per a 24-hour period is 250,000 or the number of user licenses in your organization multiplied by 200, whichever is greater
9) To test methods defined with the future annotation, call the class containing the method in a startTest(), stopTest() code block. All asynchronous calls made after the startTest method are collected by the system. When stopTest is executed, all asynchronous processes are run synchronously


IMP:-
The reason why sObjects can’t be passed as arguments to future methods is because the sObject might change between the time you call the method and the time it executes. In this case, the future method will get the old sObject values and might overwrite them.  To work with sObjects that already exist in the database, pass the sObject ID instead (or collection of IDs) and use the ID to perform a query for the most up-to-date record. The following example shows how to do so with a list of IDs

http://amitsalesforce.blogspot.in/2015/02/future-methods-in-salesforce.html

I hope below link will help you
https://help.salesforce.com/apex/HTViewSolution?id=000003701
https://help.salesforce.com/apex/HTViewSolution?id=000079772&language=en_US (https://help.salesforce.com/apex/HTViewSolution?id=000079772&language=en_US)
http://salesforce.stackexchange.com/questions/40583/you-have-uncommitted-work-pending-please-commit-or-rollback-before-calling-out

Please let us know if this will help you.

Thanks
Amit Chaudhary
amit.salesforce21@gmail.com
Bill McBill Mc
Hello to you both.  Thank you for your responses. As mentioned I dont understand why the exception is being raised within a method marked as @future which should have allowed the commit to occur. I will raise this with Salesforce directly to get an answer.  Kind regards, BIll
Greg A ShawGreg A Shaw
Bill,
Did you get a resolution on this? I'm stuggling to work out why it is happening in my instance as well.
Any pointers appreciated.
Thanks, Greg.
Bill McBill Mc
Hi Greg

No I didn't. A conultant reviewing the code suggested I was doing an email send after the callout (but still in the originating apex) which may also be prohibited. I ended up re-writing the code to do things a different way.

Bill
 
tggagnetggagne

I find it curious, Greg, that you experienced this problem the same day I first experienced it with code that had been working fine under unit tests for weeks prior.

I'm looking at the debug log of my @future method and can see no DML statements.  In fact, after issues two SOQLs, the next thing it does is a callout which returns with the "work pending" exception.

In fact, here's the debug log showing the trigger ending and the future method starting -- doing two DMLs, getting the exception, then saving a couple rows AFTER the callout.

14:34:49.737 (3972940587)|CODE_UNIT_FINISHED|CmxCaseParty on Case_Party trigger event AfterInsert for [a0A55000002CBDN]
14:34:49.737 (3973933257)|DML_END|[147]
14:34:49.737 (3973996019)|SYSTEM_MODE_EXIT|true
14:34:49.737 (3974710928)|SYSTEM_MODE_EXIT|false
14:34:49.737 (3978840126)|SYSTEM_MODE_ENTER|false
14:34:49.737 (3978884413)|USER_DEBUG|[129]|DEBUG|HandleAfterInsert()
14:34:49.737 (3978970424)|SYSTEM_MODE_ENTER|true
14:34:49.737 (3979032061)|SYSTEM_MODE_ENTER|false
14:34:49.737 (3979042156)|SYSTEM_MODE_EXIT|false
14:34:49.737 (3979090334)|SYSTEM_MODE_EXIT|true
14:34:49.737 (3979149830)|SYSTEM_MODE_ENTER|true
14:34:49.737 (3979747793)|SOQL_EXECUTE_BEGIN|[18]|Aggregations:0|SELECT supersecretfieldlist FROM supersecretobject WHERE Id = :tmpVar1
14:34:49.737 (3985750057)|SOQL_EXECUTE_END|[18]|Rows:1
14:34:49.737 (3986564011)|SYSTEM_MODE_ENTER|false
14:34:49.737 (3986935147)|USER_DEBUG|[118]|DEBUG|party afterInsert(1)
14:34:49.737 (3986945505)|SYSTEM_MODE_EXIT|false
14:34:49.737 (3987609357)|SOQL_EXECUTE_BEGIN|[26]|Aggregations:0|SELECT moresupersecretfields FROM Account WHERE id IN :tmpVar1
14:34:49.737 (3990840342)|SOQL_EXECUTE_END|[26]|Rows:1
14:34:49.737 (3992608053)|SYSTEM_MODE_ENTER|false
14:34:49.737 (3992788013)|SYSTEM_MODE_EXIT|false
14:34:49.737 (3993124627)|EXCEPTION_THROWN|[79]|System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out
14:34:49.737 (3993343664)|SYSTEM_MODE_ENTER|false
14:34:49.737 (3993486316)|SYSTEM_MODE_EXIT|false
14:34:49.737 (3993563824)|SYSTEM_MODE_ENTER|false
14:34:49.737 (3993699035)|SYSTEM_MODE_EXIT|false
14:34:49.737 (3993765709)|DML_BEGIN|[112]|Op:Update|Type:SObject|Rows:2