0

If I have some code doing DML which runs a trigger, and then that trigger throws an unhandled exception, how can I get the real cause of the problem?

For example, suppose I have a really dumb trigger:

trigger AccountTrigger on Account (after insert) {
    insert new Lead();
}

This will always fail because it's not specifying the required fields for Lead.

Then, I write a test to see whether or not I can catch the cause of the exception to be REQUIRED_FIELD_MISSING:

@IsTest
private class ChainedTriggerErrorTest {

    static Account toInsert = new Account(Name = 'ACME');

    @IsTest
    static void allOrNothingFalse() {

        Database.SaveResult result = Database.insert(toInsert, false);

        System.assertEquals(1, result.getErrors().size());
        Database.Error theError = result.getErrors()[0];
        System.assertEquals(StatusCode.CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, theError.getStatusCode());
        System.assert(theError.getMessage().contains(StatusCode.REQUIRED_FIELD_MISSING.name()));

        System.debug(theError.getMessage());
    }

    @IsTest
    static void tryCatch() {
        try {
            insert toInsert;
        } catch (DmlException e) {
            System.assertEquals(StatusCode.CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, e.getDmlType(0));
            System.assertEquals(null, e.getCause());
            System.assert(e.getMessage().contains(StatusCode.REQUIRED_FIELD_MISSING.name()));

            System.debug(e.getMessage());
        }
    }
}

All of those assertions pass i.e. both methods of trapping the errors only reveal on cause, and that cause is CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY. So, you're stuck with searching the text body of the message to see what the real cause is. 

It seems insane that e.getCause() returns null when the debug of e.getMessage() is:

Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, AccountTrigger: execution of AfterInsert

caused by: System.DmlException: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [LastName, Company]: [LastName, Company]

Trigger.AccountTrigger: line 7, column 1: []

(Emphasis mine)

Obviously, this is a bit of a fake scenario, but the real-world problem could be something like catching a row lock error. I want to catch it at the top-level and just try again later. And I'd rather do that in a better way than scraping the error message. Is there any better way?

1

That's because you have nested exceptions, so the code is only seeing the higher level one, to be able to see both, both of them need to be explictly thrown/catch, for example

On account trigger

 public static void beforeInsert(List<Account> newRecords) {


    try{
        insert new lead();
    }catch(Exception e){
        System.debug('low level exception: '+e.getDmlType(0));
        throw e;
    }

Then on the developer console (or your calling class)

Account a = new Account();
a.Name = 'Hello';

try{
    insert a;
}catch(Exception e){
    System.debug('high level exception: '+e.getDmlType(0));

}

Then in the debug log I can see both exception types

enter image description here

  • Thanks for the answer, but I am using getDmlType. My code says: "System.assertEquals(StatusCode.CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, e.getDmlType(0));". Your code would work because the error is directly in your test, not from an unhandled trigger error – Aidan Oct 28 at 11:22
  • @Aidan see my edited answer – CommonCoreTawan Oct 28 at 11:34
  • Thanks again, but the question is how to get the error type from the calling code. Inside the trigger, I can't make a decision about what to do with an unexpected exception. In the calling code, I can make a decision: report it to the user, or retry, or whatever. And that decision may depend on the low level exception type – Aidan Oct 28 at 11:45
  • So I'd argue that the exception needs to be relevant to the calling code/client/end user, and only the lower level modules/classes should care about the details. For an end user, the result is that the record wasn't saved...they don't have control on the fact that the record calls a trigger which does something wrong. So the best thing to do is to show the error, and let the user report it (or report it automatically). I've never seen an example where the end user/client code needs to be aware of low level exception details. – CommonCoreTawan Oct 28 at 11:52
  • And your example here is obviously not realistic. How can the user be expected to provide required fields for a lead, when creating an account? If you can find a proper business scenario for this, then it might be an interesting discussion. – CommonCoreTawan Oct 28 at 11:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.