Skip to main content

SF-0388 · Scenario · Medium

What would happen if we added more than 100 jobs like 125 jobs at a time?

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

Once you’ve reached the limit — 5 Processing + 100 Holding = 105 jobs in the system — any additional Database.executeBatch call throws:

System.LimitException: Attempt to add a job to the apex flex queue failed because the queue is full.

If you tried to enqueue 125 jobs in a tight loop, the first 105 would queue successfully, and jobs 106 through 125 would all throw — no automatic backoff, no retry.

The behavior

for (Integer i = 0; i < 125; i++) {
    try {
        Database.executeBatch(new MyBatch(), 200);
    } catch (System.LimitException e) {
        System.debug('Job #' + i + ' rejected: ' + e.getMessage());
    }
}

Typical debug output:

Job #105 rejected: Attempt to add a job to the apex flex queue failed...
Job #106 rejected: Attempt to add a job to the apex flex queue failed...
...
Job #124 rejected: Attempt to add a job to the apex flex queue failed...

(Jobs 0–104 succeed; 105–124 fail.)

Why this matters

This trap is most common when:

  • A trigger naively kicks off a batch for every record in a bulk load.
  • A scheduled job runs every minute, but each run takes more than a minute (jobs pile up).
  • Code submits dozens of “small” batches instead of one larger one.

How to handle it

Option 1: Check the queue first

Integer holding = [SELECT COUNT() FROM AsyncApexJob
                   WHERE Status = 'Holding' AND JobType = 'BatchApex'];
Integer processing = [SELECT COUNT() FROM AsyncApexJob
                      WHERE Status = 'Processing' AND JobType = 'BatchApex'];

if (holding + processing < 105) {
    Database.executeBatch(new MyBatch());
} else {
    // Defer: write to a custom object, retry later, or alert
}

Not race-safe (another transaction could submit before yours), but a reasonable guard for bulk inserts.

Option 2: Single batch, not many

The right design is usually one batch processing all the records, not many small batches. If you have 10,000 records to process:

  • Wrong: 10,000 small batches, each processing one record.
  • Right: 1 batch processing 10,000 records in chunks of 200 = 50 internal chunks, 1 slot used.

Option 3: Queueable instead

Queueable jobs use a different queue with a much higher limit (the per-transaction count is 50, but org-wide capacity is huge). For lots of small async tasks, Queueable scales better than batch.

Option 4: Retry with delay

Schedule a retry via Schedulable for a minute or two later:

try {
    Database.executeBatch(new MyBatch());
} catch (System.LimitException e) {
    System.scheduleBatch(new MyBatch(), 'Retry MyBatch ' + Datetime.now(), 5);
}

System.scheduleBatch schedules the batch to start later, allowing the queue to drain.

Common interview follow-ups

  • Are the 5 processing slots org-wide or per user? — Org-wide.
  • Does the limit count Queueable, Future, Scheduled? — No — only batch jobs.
  • Is there a per-user version of this limit? — No, it’s purely org-level.
  • What’s the daily async limit? — 250,000 jobs/24 hours, or 200 × user licenses, whichever is greater. Different from the Flex Queue cap.

Verified against: Apex Developer Guide — Apex Flex Queue Limits. Last reviewed 2026-05-17.