Thursday, March 27, 2014

How to solve: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY: maximum trigger depth exceeded “S object” error?

(Wow that is the longest title I've ever given a blog! You searched on your error message and you found my post, right? Now, to the issue-at-hand.)
Trigger recursion is a big nightmare for the Salesforce developer. When a trigger with odd criteria (malformed?) fires; it subsequently starts auto firing and results in an exception error; something like:

CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, Update_Opportunity_Calculation_fields: maximum trigger depth exceeded “S object”

In order to solve this we use the help of a static variable.  Create an apex class with static Boolean variables and add a check in the trigger for specified Boolean  value results.

Here's an example:

My business case is that I wish to renew a subscription on an Account. I want to automatically create a new Opportunity. In this scenario, I wish to create another Opportunity, say a related child Opportunity, when a master Opportunity is inserted. I've created a after insert trigger on Opportunity. When I insert a new record, it gets fired.

Look at the code:
trigger recurssiontest on opportunity(after insert) {
     for(opportunity opp:trigger.new){
       opportunity o = new opportunity();
       o.Name='xyz child';
       o.parentid__c=opp.id; //id of the parent
       insert o;
     } 
}
This code will return: error CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, Update_Opportunity_Calculation_fields: maximum trigger depth exceeded “S object”

So what’s the work around ?

Create a apex class with global or public access specifier and call the apex class inside the trigger in an IF statement. This will check to see, if the static variables inside the apex class meets the specified conditions.

Like this:
public class stoprecurssion{
public static boolean flag=true;
public static boolean runonce(){
if(flag){
   flag=false;
  }
else {
   return flag;
  }
   return true;
 }
}
In the trigger, never forget to add the IF check, which is called from the instance of the above class.

It will look like this:
trigger recurssiontest on opportunity(after insert) {
     for(opportunity opp:trigger.new){
      if(stoprecurssion.runonce()){
       opportunity o= new opportunity();
       o.Name='xyz child';
       o.parentid__c=opp.id; //id of the parent
       insert o;
       }
     }
}
Writing our trigger in this manner, avoids recursive firing of triggers.

No comments: