+ Start a Discussion
aaronbaumanaaronbauman 

try / catch fails to catch System.LimitException

My entire APEX trigger is wrapped in a try/catch block, catching the generic Exception object, but I'm still hitting a fatal System.LimitException.

 

What's the point of try/catch if it doesn't actually catch an exception? 

How can I make sure my try / catch block prevents a fatal error?

 

Here's the relevant snippet:

 

for (Contact c : [SELECT Email, Id FROM Contact WHERE AccountId = :account_id LIMIT 10]) {
  if(c.Email != null){
    try {
      Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
      message.setTemplateID(email_template.Id);
      message.setWhatId(detail.Id);
      message.setTargetObjectId(c.Id);
      Messaging.sendEmail(new Messaging.SingleEmailMessage[] { message });
    }    

    catch (System.LimitException e) {

      // I don't really care if the email fails.

      // I just don't want it to break my data entry process.

     }

     catch (Exception e) {

      // I don't really care if the email fails.

      // I just don't want it to break my data entry process.
    }
  }

}

 

updated: even explicitly catching system.limitexception fails.

Best Answer chosen by Admin (Salesforce Developers) 
Ron HessRon Hess

 

The docs do explain that limits excpetions cannot be caught.

 

I do something like this :

 

/** 
	 * @description while processing records, 
	 * monitor our query count and throw a custom 
	 * exception to allow us to move the processing into a batch job
	 */   
   	public static void checkGovenorLimits() { 
   		if (Limits.getQueries() +  limit_queries >= Limits.getLimitQueries() ) {
   			throw new KseLimitException();
   		}
   		if(Limits.getDmlRows() + limit_dmlrows>= Limits.getLimitDmlRows()){
   			throw new KseLimitException();
   		}
}

 

 

Then in your loops, you call checkGovenorLimits() often

 

 

All Answers

Ron HessRon Hess

 

The docs do explain that limits excpetions cannot be caught.

 

I do something like this :

 

/** 
	 * @description while processing records, 
	 * monitor our query count and throw a custom 
	 * exception to allow us to move the processing into a batch job
	 */   
   	public static void checkGovenorLimits() { 
   		if (Limits.getQueries() +  limit_queries >= Limits.getLimitQueries() ) {
   			throw new KseLimitException();
   		}
   		if(Limits.getDmlRows() + limit_dmlrows>= Limits.getLimitDmlRows()){
   			throw new KseLimitException();
   		}
}

 

 

Then in your loops, you call checkGovenorLimits() often

 

 

This was selected as the best answer
aaronbaumanaaronbauman

Thanks, I did end up doing something similar.

I like your approach for pre-emptively throwing a catchable exception.

 

I don't understand how one class of Exceptions can be caught and another cannot.

I'm sure there's some sound technical reason behind this limitation, but I think un-catchable exceptions should be classed differently than other exceptions.

 

 

sfdcfoxsfdcfox

Governor limits are the only exception you can't catch. Consider the following:

 

try {
  for( integer i = 0; i < 5; i++ ) {
    i--;
  }
} catch( exception e ) {
// Catch that pesky infinite loop exception, we know what we're doing.
}

This wholesomely faux code demonstrates the point of uncatchable exceptions; if they were catchable, you could work around those limits, and they simply are not up for debate. In theory, you could cause a hanging thread if you wrote a clever enough infinite loop that could catch exceptions. Alternatively, assuming this limit check were checked every single statement (which it is), your try-catch block would needlessly fail to execute anyways (because it would in turn throw "too many statements").

 

The theory of what you have in the solution is ideal; always make sure you won't exceed your limits before execution. You could make classes that, for example, defer part of their work to an asynchronous function if it can't complete it within the available limits.

Vaibhav Soni 6Vaibhav Soni 6
Hi Ron
Its Amazing, but can you tell me What is "limit_queries" and "limit_dmlrows" and how did you fetch them.