Skip to main content

SF-0357 · Scenario · Hard

Given a scenario where we have written a future call in the Opportunity Trigger update operation. And we have a batch job running on opportunity records and updates the records, Does the future call be invoked after the update?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

No — the future method does NOT fire, and worse, the batch chunk throws an AsyncException and fails.

What’s happening step by step

  1. Batch Apex starts, execute runs with a chunk of Opportunities.
  2. execute issues update opportunities;
  3. Salesforce fires the Opportunity update trigger.
  4. The trigger calls MyClass.doAsyncWork(ids); — a @future method.
  5. The platform detects: “this is a future call inside a batch transaction” — throws:

System.AsyncException: Future method cannot be called from a future or batch method.

The chunk fails. The opportunities in that chunk are rolled back. The batch moves to the next chunk and the same thing happens. Every chunk fails. The future method never executes for any record touched by the batch.

The full failure chain

public class OpptySyncBatch implements Database.Batchable<sObject> {
    public Database.QueryLocator start(Database.BatchableContext ctx) {
        return Database.getQueryLocator('SELECT Id, StageName FROM Opportunity WHERE IsClosed = false');
    }
    public void execute(Database.BatchableContext ctx, List<Opportunity> scope) {
        for (Opportunity o : scope) o.StageName = 'Qualification';
        update scope; // triggers OpportunityTrigger
    }
    public void finish(Database.BatchableContext ctx) {}
}

trigger OpportunityTrigger on Opportunity (after update) {
    Set<Id> ids = new Set<Id>();
    for (Opportunity o : Trigger.new) ids.add(o.Id);
    OpptyAsync.callExternal(new List<Id>(ids)); // <-- AsyncException
}

public class OpptyAsync {
    @future(callout=true)
    public static void callExternal(List<Id> ids) { /* never runs */ }
}

What the user sees:

  • AsyncApexJob.Status = 'Failed' (or Completed with NumberOfErrors > 0)
  • Every error message says “Future method cannot be called from a future or batch method”
  • Zero records updated in the org

Why Salesforce blocks this

A batch processing 1 million records in 5,000 chunks could enqueue 5,000 future calls in seconds if this were allowed. That would either flood async capacity or trigger an outage-level fan-out. The rule is simple and absolute: batch transactions cannot enqueue future methods.

The same rule applies to future-from-future and future-from-batch — see the related questions.

Common interview follow-ups

  • Will the batch retry the failed chunks? — No, Batch Apex doesn’t auto-retry. You’d re-run the batch manually after fixing the code.
  • Does only DML inside execute cause it? — Any path from execute (or start/finish) to a future call fails — whether it’s a direct call, a trigger handler invocation, a flow that calls Apex, anything.
  • What if the trigger guards against future calls in batch context? — Then the trigger doesn’t throw. See the next question for how to detect batch context.

Verified against: Apex Developer Guide — Batch Apex Limitations. Last reviewed 2026-05-17.