0

With Apex, after calling .addError() on a trigger record is there any way to subsequently remove that error such that the DML operation will complete successfully?

I don't see any Database methods (nor DMLOptions) like .ignoreErrors() nor any SObject methods like .removeErrors() or .clearErrors().


(Before you ask if this might be an XY problem, suffice it to say the option of not calling .addErrors() in the first place will entail much more work.)

1 Answer 1

1

Once you add an error, you cannot remove that error. The DML operation is doomed to fail. However, what happens next is defined by the callee. When allOrNone=true, the default, a DML exception is thrown, which the callee can deal with. If the callee sets allOrNone=false, then Salesforce automatically takes care of automatic retries. This means that any client, be it Apex Code, a SOAP or REST API call, etc, can determine if partial success is an acceptable outcome.

When partial saves are allowed on a DML operation, a checkpoint is set by the system before it starts, and all records are processed. If there are no errors, the callee regains control. If there was an error, those records are set aside, the governor limits are reset back to the point where the checkpoint was set, and the remaining records are tried again. If any new errors come up, they will likewise be set aside, and a third attempt is performed. If there are any errors at this point, you get the "Too many batch retries in the presence of Apex triggers and partial failures" exception.

This behavior even works recursively. If you have a trigger that updates other records, and allows a partial save, you can then add errors back up the trigger stack to perform complicated retries with minimal effort. And, since the governor limits are reset back to the checkpoint, even if there are multiple layers, it means you'll have more governor limit time to complete your transactions, even in the face of multiple recursive errors.

In other words, it is not the callee's responsibility to remove errors, but rather the callee specifying an intent to allow partial saves. For completeness, you should always consider using allOrNone=false in your own DML logic, and always using addError to generate errors that can lead to a partial success. It's a very clean way of dealing with errors in a consistent manner. I even once wrote an entire library around it that handled recursive partial errors.

It became handy to write things like:

DmlUtils.insertRecords(records, parentRecords);

Where this method would perform all the necessary logic to do partial retries and propagate errors back to the parent records for recursive retries. It doesn't even require that much code and is completely reusable.

4
  • 2
    The most significant "gotcha" with an allOrNone = false DML operation is that static variables are not reset/rolled back. An 'allOrNone = false insert will also toss out and re-assign Ids (a completely new set of Ids) if there are any failures within a given chunk of 200 records.
    – Derek F
    May 10 at 23:32
  • @DerekF I agree, it'd be nice if the system was smart enough to do that for us. Static variables are kind of horrible to begin with (in the regular programming world, we say "global variables are Evil.") Of course, they can be managed, and should be, it just requires some additional conscious design decisions.
    – sfdcfox
    May 10 at 23:36
  • Great answer, and helpful background, though in my case I don't always control the calling context that initiates the DML - a set of contexts that includes plain inserts/updates from the SF UI - so specifying allOrNone = false by the client isn't an option in my case. (Should have specified that in the question.) May 11 at 3:19
  • 1
    @BrentBowers Well, that's kind of the point, though. If the caller expects all or none, and you somehow allowed partial results, that would violate the atomicity rule of an ACID-compliant database. Since atomicity has already been determined by the caller, you must also follow those rules for a consistent database.
    – sfdcfox
    May 11 at 13:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .