DML executed inside a catch block
ID |
apex.correctness.dml_in_catch_block |
Severity |
high |
Remediation Complexity |
medium |
Remediation Risk |
medium |
Remediation Effort |
medium |
Resource |
Error Handling |
Language |
Apex |
Description
Reports a DML statement - insert, update, upsert, delete - written inside a catch block.
Rationale
A catch block runs while the transaction is already in trouble, and DML there can fail for its own reasons: the new exception replaces the original one, so the log records the failure of the error handler instead of the failure it was handling. If the first exception was a LimitException the second DML cannot succeed at all, and if the transaction is later rolled back, the row the handler wrote - usually the error log entry - disappears with it, which is exactly the record that was supposed to survive.
The following code illustrates the pattern detected by this rule:
public class ErrorLogging {
public void save(Account a) {
// FLAGGED: DML executed inside a catch block
try {
insert a;
} catch (DmlException e) {
insert new Error_Log__c(Message__c = e.getMessage());
}
}
public void saveWithEvent(Account a) {
try {
insert a;
} catch (DmlException e) {
EventBus.publish(new Error_Event__e(Message__c = e.getMessage()));
}
}
}
Remediation
Collect what needs to be recorded and write it outside the try/catch, or persist it in a way that survives a rollback - Database.insert with allOrNone=false, a platform event published with EventBus.publish, or a separate Queueable. Keep the catch block itself to logging and adding the error to the record.