How to Fix “Maximum Stack Depth” Error?

Spread the love

Question

The “Maximum stack depth has been reached” error often occurs in Salesforce when there is an excessive chain of asynchronous operations, such as Queueable or Future calls, leading to a recursive or circular flow. This error is especially common when testing complex asynchronous logic with triggers and schedulable or queueable classes. Here, we’ll address a specific scenario and provide solutions.

A user has a setup where triggers handle lead suppression by enqueuing asynchronous jobs. Each trigger calls a Queueable or Schedulable class based on certain conditions, as shown in the provided example.

Trigger Example:

trigger HandleLeadSuppressionTrigger on Lead (after insert, after update) {
    Set<Id> leadIds = new Set<Id>();

    for (Lead lead : Trigger.new) {
        if (Trigger.isInsert) {
            if (lead.Related_Account__c != null || lead.Email != null || lead.Phone != null || lead.Related_Contact__c != null || 
                (lead.PostalCode != null && lead.Company != null)) {
                leadIds.add(lead.Id);
            }    
        }
        if (Trigger.isUpdate) {
            Lead oldLead = Trigger.oldMap.get(lead.Id);
            if ((lead.Related_Account__c != null && lead.Related_Account__c != oldLead.Related_Account__c) ||
                (lead.Email != null && lead.Email != oldLead.Email) || 
                (lead.Phone != null && lead.Phone != oldLead.Phone) || 
                (lead.Related_Contact__c != null && lead.Related_Contact__c != oldLead.Related_Contact__c) || 
                ((lead.PostalCode != null && lead.PostalCode != oldLead.PostalCode) && 
                 (lead.Company != null && lead.Company != oldLead.Company))) {
                leadIds.add(lead.Id);
            }
        }
    }
    
    if (!leadIds.isEmpty()) {
        if (Limits.getLimitQueueableJobs() - Limits.getQueueableJobs() > 0) {
            System.enqueueJob(new SuppressionQueue(null, null, null, leadIds));
        } else {
            String cronExp = Datetime.now().format('s m H d M ? yyyy');
            System.schedule('Lead Suppression Job ' + Datetime.now(), cronExp, new SuppressionScheduler(null, null, null, leadIds));
        }
    }
}

Schedulable Class Example:

public class SuppressionScheduler implements Schedulable  {
    Set<Id> leadIds;

    public SuppressionScheduler(Set<Id> leadIds) {
        this.leadIds = leadIds;
    }

    public void execute(SchedulableContext sc) {
        if (leadIds != null && !leadIds.isEmpty()) {
            System.enqueueJob(new SuppressionQueue(null, null, null, leadIds));
        }
    }
}

This approach can inadvertently cause chained asynchronous operations, especially during testing, resulting in the stack depth error.

Answer

The user resolved the issue by refactoring the logic to eliminate unnecessary layers of asynchronous chaining. Specifically, the SuppressionQueue class was removed, and the triggers and SuppressionScheduler directly called the Queueable classes performing DML operations.

Here is the refactored logic:

Trigger Example (Refactored):

trigger HandleLeadSuppressionTrigger on Lead (after insert, after update) {
    Set<Id> leadIds = new Set<Id>();

    for (Lead lead : Trigger.new) {
        if (Trigger.isInsert) {
            if (lead.Related_Account__c != null || lead.Email != null || lead.Phone != null || lead.Related_Contact__c != null || 
                (lead.PostalCode != null && lead.Company != null)) {
                leadIds.add(lead.Id);
            }    
        }
        if (Trigger.isUpdate) {
            Lead oldLead = Trigger.oldMap.get(lead.Id);
            if ((lead.Related_Account__c != null && lead.Related_Account__c != oldLead.Related_Account__c) ||
                (lead.Email != null && lead.Email != oldLead.Email) || 
                (lead.Phone != null && lead.Phone != oldLead.Phone) || 
                (lead.Related_Contact__c != null && lead.Related_Contact__c != oldLead.Related_Contact__c) || 
                ((lead.PostalCode != null && lead.PostalCode != oldLead.PostalCode) && 
                 (lead.Company != null && lead.Company != oldLead.Company))) {
                leadIds.add(lead.Id);
            }
        }
    }

    if (!leadIds.isEmpty()) {
        System.enqueueJob(new SuppressionQueueable(leadIds));
    }
}

Queueable Class:

public class SuppressionQueueable implements Queueable {
    Set<Id> leadIds;

    public SuppressionQueueable(Set<Id> leadIds) {
        this.leadIds = leadIds;
    }

    public void execute(QueueableContext context) {
        // Perform the DML operations for lead suppression
    }
}

Key Takeaways

  1. Avoid chaining too many asynchronous calls in one flow. Each asynchronous operation consumes system resources and contributes to stack depth.
  2. Refactor unnecessary classes and simplify the flow wherever possible.
  3. Test thoroughly after changes to ensure the logic still meets business requirements.

With this refactoring, the “Maximum stack depth” error was resolved, and the test cases ran successfully.

Summing Up

The “Maximum stack depth has been reached” error in Salesforce occurs when excessive asynchronous calls, such as Queueable or Schedulable jobs, are chained, causing resource limits to be exceeded. In the provided example, the original trigger and scheduler logic used multiple asynchronous layers, leading to this error during testing.

The issue was resolved by refactoring the code to simplify the flow. The HandleLeadSuppressionTrigger was modified to directly enqueue a Queueable class (SuppressionQueueable) instead of relying on intermediate layers like the SuppressionQueue class. This approach reduced complexity, avoided excessive asynchronous chaining, and adhered to best practices.

Enroll for Salesforce Training Designed for Career Building Success

Our Salesforce Course is designed to provide you with a comprehensive understanding of the Salesforce platform, empowering you with the skills necessary for success in the CRM space. We cover essential modules such as Salesforce Admin, Developer, and AI, combining theoretical knowledge with hands-on learning.

Through real-time project work and practical assignments, you’ll be prepared to solve complex business problems using Salesforce solutions. Our experienced instructors ensure that you gain the practical skills and industry insights needed to thrive in the Salesforce ecosystem.

Along with in-depth technical training, our Salesforce training in Chennai offers personalized mentorship, certification guidance, and interview preparation to give you an edge in the competitive job market. You will receive detailed study materials, practical exposure through live projects, and one-on-one assistance throughout the course.

By the end of the training, you will not only be ready for certification exams but also equipped with the hands-on experience and problem-solving abilities that employers are seeking. Start your Salesforce journey with us and unlock the door to exciting career opportunities! Enroll for FREE demo!


0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x
Open Chat
1
Dear Sir/Madam
How can I help you?