Catch a DmlException and read its details
DML operations · Intermediate · 14 min · Runs in your Salesforce Developer org · Apex Path
Default DML is all-or-none: if any row fails, Apex throws `DmlException`, and the exception knows which row failed and why. Catch it from an all-or-none insert of a valid and an invalid Account, then read the failed row's index and status code. Because nothing is saved under all-or-none, a follow-up query also returns zero.
Lesson
Why this matters
Bulk loaders and migrations run DML on dozens of rows at once. When one row is wrong, the default insert throws DmlException and nothing saves. You need to know which row failed and why, so the next retry can skip or fix just that row.
The smallest working example
try {
insert rows;
} catch (DmlException dmlError) {
Integer failedIndex = dmlError.getDmlIndex(0);
String code = String.valueOf(dmlError.getDmlType(0));
System.debug(failedIndex);
System.debug(code);
}
The index points into the input list. The status is a Salesforce enum like REQUIRED_FIELD_MISSING.
Name the parts
- **
try { insert rows; }** runs the DML. If any row fails, the rest of the block is skipped. - **
catch (DmlException dmlError)** names the type thrown by DML errors. Other exceptions do not match. - **
getDmlIndex(0)** returns the first failed row's position in the input list. - **
getDmlType(0)** returns the Salesforce status enum (for exampleREQUIRED_FIELD_MISSING). - All-or-none DML means a single failure rolls back the whole statement. A later query sees no saved rows.
A common wrong version
try {
insert rows;
} catch (Exception e) {
System.debug('something failed');
}
Catching plain Exception works, but you lose the row-level helpers. e.getDmlIndex(0) does not compile on an Exception variable.
The fix
Catch DmlException so you can read the row-level details:
try {
insert accounts;
} catch (DmlException dmlError) {
failedIndex = dmlError.getDmlIndex(0);
statusCode = String.valueOf(dmlError.getDmlType(0));
}
Now you try
Wrap the starter's insert accounts in try/catch (DmlException dmlError), read index and status in the catch, then count what was saved. Print Failed index:, Status code: and Saved count: in that order.
Learn more
The challenge
Insert a list with one valid and one invalid Account and read what went wrong from the DmlException.
Examples:
- The invalid row is the second entry →
Failed index: 1 - The missing field is Name →
Status code: REQUIRED_FIELD_MISSING - Nothing is saved because of all-or-none →
Saved count: 0
Requirements:
catch (DmlExceptionshould be present around the insert..getDmlIndexshould be present in the catch.Failed index: 1should be printed from the caught exception.Status code: REQUIRED_FIELD_MISSINGshould be printed from the caught exception.Saved count: 0should be printed from a count query by tag.
Starter code
String tag = 'AS-D310-' + UserInfo.getUserId() + '-' +
String.valueOf(Datetime.now().getTime());
List<Account> accounts = new List<Account>{
new Account(Name = tag + '-Valid'),
new Account()
};
Integer failedIndex = -1;
String statusCode = 'NONE';
Related drills
- Insert an Account with Contacts
- Undelete from the Recycle Bin
- Roll back parent and children on a child failure
You write the Apex yourself. ApexSensei runs it and tells you what passed and what did not.
‹ Insert an Account with Contacts · Undelete from the Recycle Bin ›