Database operation results are never inspected

ID

apex.correctness.saveresult_errors_unchecked

Severity

high

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Error Handling

Language

Apex

Description

Reports a method that assigns the results of a Database.insert / update / upsert / delete call and never iterates them.

Rationale

The Database.* methods exist to allow partial success: rows that fail are reported in the result list instead of throwing, and the transaction carries on. That is only useful if something reads the list. Left unread, every rejected row - a validation rule, a required field, a duplicate key - disappears without an exception, without a log line and without a rollback, and the caller reports success for a load that only partly happened. The missing records are found later by whoever reconciles the two systems, with nothing in the org to say what went wrong or when.

The following code illustrates the pattern detected by this rule:

public class BulkLoader {

    // FLAGGED: Database operation results are never inspected
    public void loadAccounts(List<Account> accounts) {
        List<Database.SaveResult> results = Database.insert(accounts, false);
        System.debug('loaded ' + accounts.size());
    }

    // FLAGGED: Database operation results are never inspected
    public void upsertContacts(List<Contact> contacts) {
        List<Database.UpsertResult> results = Database.upsert(contacts, Contact.Fields.Email, false);
        System.debug('upserted');
    }

    public void loadAccountsChecked(List<Account> accounts) {
        List<Database.SaveResult> results = Database.insert(accounts, false);
        for (Database.SaveResult r : results) {
            if (!r.isSuccess()) {
                System.debug(LoggingLevel.ERROR, r.getErrors());
            }
        }
    }

    public void loadAccountsAllOrNone(List<Account> accounts) {
        insert accounts;
    }
}

Remediation

Iterate the results, and for each one that is not successful, read getErrors() and do something with it - write a row to a logging object, collect the failures for the caller, or add the error back onto the record. Where partial success is not wanted at all, use the DML statement (insert accounts;) so a failure throws and rolls the transaction back.

Configuration

This detector does not need any configuration.

© 2026 Xygeni. All rights reserved