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
[Lindsey Kiken][Lindsey Kiken] 

ReasonUnderReview: maximum trigger depth exceeded Error

I am new to apex coding, especially code that involves mult-select picklists, so please bear with me!

I have a multi-select picklist on the Contact object called Reason_Under_Review__c that I am working on coding to automatically populate with values that are depented on specific values within the Contact record to == TRUE. My current code is as follows:
 
trigger ReasonUnderReview on Contact (after insert, after update) {

//(1) define variable for list of all UnderReviewIDs
List<Id> UnderReviewIDs = new List<ID>();
      for(Contact c: trigger.new){
      if(c.Reason_Under_Review__c == null){
          UnderReviewIDs.add(c.id);
          }
}  
//(2) get ids and fields on the Contact record
List<Contact> underreviewreasons = new List<Contact>();
for(Contact c: [SELECT Id,FirstName,LastName,Email,Reason_Under_Review__c
                                                FROM Contact
                                                WHERE Id in: UnderReviewIDs]) {
                                                
//(3) select Under Review Reasons based on fields on the Contact record                                                                                          
        if(c.FirstName==null){c.Reason_Under_Review__c += ';Missing First Name ';}
        if(c.LastName==null){c.Reason_Under_Review__c +=';Missing Last Name ';}
        if(c.Email==null){c.Reason_Under_Review__c +=';Missing Email Address ';}
        c.Reason_Under_Review__c = c.Reason_Under_Review__c.replaceAll(';?null;?','');
        
        underreviewreasons.add(c);
        
//(4) update Reason_Under_Review__c field
}
update underreviewreasons;
}

So far, I see two glaring issues with the code above:
  1. I can only get this code to fire when the Reason_Under_Review__c field == null on Line 6. This means that if the trigger has ever previously fired and populated the field with a value, the trigger will no longer fire any additional updates.
    • If I change Line 6 to say RecordTypeID = [18digit record type ID in my test org] or Reason_Under_Review__c != null, I get a large "ReasonUnderReview: maximum trigger depth exceeded" error when trying to save my test Contact record.
    • I believe that this issue might be due to recursive errors, but am a bit lost on how to fix the issue. How do I resolve this error in my code?
  2. This code is very obviously not setup right now to conditionally delete multi-select picklist values, if the criteria does not meet the condition for the value to exist within the field.
    • A quick example would be that the Contact record previously did not have a FirstName value, and has since updated the record. Per Line 17, the field would have been stamped with a "Missing First Name" value, but I have nothing in place to conditional remove said value when it no longer rings true.
    • How do I conditionally delete values within a multi-select picklist field?
Please let me know if you have any questions and thank you so much for your help regarding this matter!

Cheers,
Lindsey
Best Answer chosen by [Lindsey Kiken]
UC InnovationUC Innovation
Hi Lindsey,

1) The recursion is because you are firing the trigger on after update, and you're calling an update on a list of contacts in the trigger. You can solve this problem by writing a class to check for a recursive call. 

2) One way to do this is instead of appending values to the field, just set the field to empty first and populate based on your criteria.

Here's the class code:
 
public Class checkRecursive{
    private static boolean run = true;
    public static boolean runOnce(){
        if (run){
            run = false;
            return true;
        }
        else
        {
            return run;
        }
    }
}
And you would have to modify your trigger code like this:
 
trigger ReasonUnderReview on Contact (after insert, after update) {

    if (checkRecursive.runOnce()){

        //(1) define variable for list of all UnderReviewIDs
        List<Id> UnderReviewIDs = new List<ID>();
              for(Contact c: trigger.new){
              if(c.Reason_Under_Review__c == null){
                  UnderReviewIDs.add(c.id);
                  }
        }  
        //(2) get ids and fields on the Contact record
        List<Contact> underreviewreasons = new List<Contact>();
        for(Contact c: [SELECT Id,FirstName,LastName,Email,Reason_Under_Review__c
                                                        FROM Contact
                                                        WHERE Id in: UnderReviewIDs]) {
                                                        
        //(3) select Under Review Reasons based on fields on the Contact record         

                // ADDED THIS LINE
                c.Reason_Under_Review__c = '';
                
                if(c.FirstName==null){c.Reason_Under_Review__c += ';Missing First Name ';}
                if(c.LastName==null){c.Reason_Under_Review__c +=';Missing Last Name ';}
                if(c.Email==null){c.Reason_Under_Review__c +=';Missing Email Address ';}
                c.Reason_Under_Review__c = c.Reason_Under_Review__c.replaceAll(';?null;?','');
                
                underreviewreasons.add(c);
                
        //(4) update Reason_Under_Review__c field
        }
        
        update underreviewreasons;
    }
}
Let me know how that works!

All Answers

UC InnovationUC Innovation
Hi Lindsey,

1) The recursion is because you are firing the trigger on after update, and you're calling an update on a list of contacts in the trigger. You can solve this problem by writing a class to check for a recursive call. 

2) One way to do this is instead of appending values to the field, just set the field to empty first and populate based on your criteria.

Here's the class code:
 
public Class checkRecursive{
    private static boolean run = true;
    public static boolean runOnce(){
        if (run){
            run = false;
            return true;
        }
        else
        {
            return run;
        }
    }
}
And you would have to modify your trigger code like this:
 
trigger ReasonUnderReview on Contact (after insert, after update) {

    if (checkRecursive.runOnce()){

        //(1) define variable for list of all UnderReviewIDs
        List<Id> UnderReviewIDs = new List<ID>();
              for(Contact c: trigger.new){
              if(c.Reason_Under_Review__c == null){
                  UnderReviewIDs.add(c.id);
                  }
        }  
        //(2) get ids and fields on the Contact record
        List<Contact> underreviewreasons = new List<Contact>();
        for(Contact c: [SELECT Id,FirstName,LastName,Email,Reason_Under_Review__c
                                                        FROM Contact
                                                        WHERE Id in: UnderReviewIDs]) {
                                                        
        //(3) select Under Review Reasons based on fields on the Contact record         

                // ADDED THIS LINE
                c.Reason_Under_Review__c = '';
                
                if(c.FirstName==null){c.Reason_Under_Review__c += ';Missing First Name ';}
                if(c.LastName==null){c.Reason_Under_Review__c +=';Missing Last Name ';}
                if(c.Email==null){c.Reason_Under_Review__c +=';Missing Email Address ';}
                c.Reason_Under_Review__c = c.Reason_Under_Review__c.replaceAll(';?null;?','');
                
                underreviewreasons.add(c);
                
        //(4) update Reason_Under_Review__c field
        }
        
        update underreviewreasons;
    }
}
Let me know how that works!
This was selected as the best answer
[Lindsey Kiken][Lindsey Kiken]
Thank you for your help on this, UC Innovation! I knew it was a simple fix and was really kicking myself for not knowing it! In My particular predicament, Line 8 in your suggested trigger code was still giving me grief. Fixing that to work with my org, as well as making some minor formatting adjustments, I came up with this as the final working code:
 
trigger ReasonUnderReview on Contact (after insert, after update) {

    if (checkRecursive.runOnce()){

//(1) define variable for list of all UnderReviewIDs
        
        List<Id> UnderReviewIDs = new List<ID>();
              for(Contact c: trigger.new){
              if(c.RecordTypeID == '012220000004LpL'){
                  UnderReviewIDs.add(c.id);
                  }
        }  
        
//(2) get ids and fields on the Contact record
        
        List<Contact> underreviewreasons = new List<Contact>();
        for(Contact c: [SELECT Id,FirstName,LastName,Email,Reason_Under_Review__c
                                                        FROM Contact
                                                        WHERE Id in: UnderReviewIDs]) {

//(3) clear out the current values listed in the Under Review Reasons field

                c.Reason_Under_Review__c = '';
                
//(4) select Under Review Reasons based on fields on the Contact record  
                               
                if(c.FirstName==null){c.Reason_Under_Review__c += ';Missing First Name ';}
                if(c.LastName==null){c.Reason_Under_Review__c +=';Missing Last Name ';}
                if(c.Email==null){c.Reason_Under_Review__c +=';Missing Email Address ';}
                c.Reason_Under_Review__c = c.Reason_Under_Review__c.replaceAll(';?null;?','');
                
                underreviewreasons.add(c);
        }
        
//(5) update Reason_Under_Review__c field  
              
        update underreviewreasons;
    }
}