Trigger reads a single record from the context collection

ID

apex.correctness.triggers_process_records_bulk

Severity

high

Remediation Complexity

medium

Remediation Risk

medium

Remediation Effort

medium

Resource

Error Handling

Language

Apex

Description

Reports a trigger body taking one record out of the context collection - Trigger.new[0], Trigger.old[0], Trigger.new.get(0) - instead of processing every record it was given.

Rationale

A trigger fires once per batch of up to 200 records, not once per record. Reading index zero works for as long as the only writes are one-at-a-time edits from the UI, and then quietly stops: a Data Loader import, a bulk API call, a flow that updates a list, a batch job - each of them hands the trigger 200 records and 199 of them are skipped with no error anywhere. The data is simply wrong, and it is wrong in the rows nobody looked at, which is why this is usually found months later during a reconciliation.

The following code illustrates the pattern detected by this rule:

trigger OpportunityTrigger on Opportunity (before insert, before update, after update) {

    if (Trigger.isBefore) {
        // FLAGGED: Trigger reads a single record from the context collection
        Opportunity opp = Trigger.new[0];
        OpportunityTriggerHandler.stamp(opp);
    }

    if (Trigger.isAfter && Trigger.isUpdate) {
        // FLAGGED: Trigger reads a single record from the context collection
        Opportunity previous = Trigger.old.get(0);
        System.debug(previous.StageName);
    }

    if (Trigger.isBefore && Trigger.isUpdate) {
        OpportunityTriggerHandler.handleBeforeUpdate(Trigger.new, Trigger.oldMap);
    }

    if (Trigger.isAfter && Trigger.isInsert) {
        OpportunityTriggerHandler.handleAfterInsert(Trigger.new);
    }
}

Remediation

Iterate the whole collection, or pass it to a handler that does: collect what needs changing into a List, query the related records once into a Map keyed by id, and issue one DML statement after the loop. Where the trigger really must act on one record, select it by a condition rather than by position.

Configuration

This detector does not need any configuration.

© 2026 Xygeni. All rights reserved