How to get the underlying custom exception from a trigger’s DMLException [duplicate]

My question was previously asked but the answer in that case was unrelated. In my case, I have a class that can raise custom exceptions, and the class may be called from trigger context. When that happens, the calling code doesn’t get the custom exception, but instead gets a DMLException. Per the docs, Exception.getCause(), “Returns the cause of the exception as an exception object,” but it’s always returning null. In the debug log, I can see the original exception, for example:

System.DmlException: Update failed. First exception on row 0 with id a56W0000000UCWMIA4; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, FMZ_DisbursementTrigger: execution of AfterUpdate

caused by: FMZ_Loan.InvalidTransactionDateException: New transaction would occur before latest transaction date of: 6/28/2017

FMZ_Loan.InvalidTransactionDateException is the custom exception I’m trying to detect. For example, from a unit test:

boolean caught = false;
try {
    update disb;
}
catch(FMZ_Loan.InvalidTransactionDateException tdEx) {
    caught = true;  // THIS LINE NEVER REACHED - DMLException instead
}
catch(DMLException dmlEx) {
    Exception cause = dmlEx.getCause();
    System.assertNotEquals(null, cause);  // THIS FAILS
    System.assert(cause instanceof FMZ_Loan.InvalidTransactionDateException);
    caught = true;
}
System.assert(caught);

This isn’t just a testing issue; other code needs to understand why an update may have failed. How do I get the root cause of a DMLException?

Answer

Each DML operation (including nested operations) constitutes an entire transaction, including a rollback point. Part of the magic of DML statements is that when an exception is thrown and not caught, it is converted to a DmlException.

This is done by necessity so that API clients are able to understand the error. During the Summer ’18 release, a bug appeared briefly where an uncaught exception in a trigger was also cancelling the entire transaction without explanation, despite an outer try-catch block, but this appears to be fixed in Winter ’19.

Long story short, you must use the only approved mechanism for communicating errors: the SObject addError method. It should also be noted that a try-catch DML operation is not bulk-friendly. Using exceptions to try to communicate messages may drastically harm performance in certain situations, and will make it harder to diagnose problems, since you’ll have no idea which row caused the problem.

As for figuring out why an operation failed? Read the error messages. That’s what they are there for. A proper error message will include the field that failed as well as the message. This is all you should really need. Use custom labels if you need to support multiple languages.

Attribution
Source : Link , Question Author : Jason Clark , Answer Author : sfdcfox

Leave a Comment