Error "Too many queueable jobs added to the queue: 2"

Salesforce says you can add 50 jobs to the queue per transaction. But what Salesforce doesn't mention clearly is that it is not applicable for batch, you can only enqueue one job. Even if you enqueue your job in the trigger, you are still in a batch context.

  • Make sure you don't call enqueueJob twice at any point in the same transaction. For example an insert that would call an update and would execute enqueueJob twice.
  • Make sure you don't have enqueueJob in a for loop.
  • Make sure your code is bulkify.

You have two things going on here:

  1. You can only execute one job from a job.
  2. Triggers fire in chunks of 200 records.

So if you update 201 records, you will have one Queueable kicked off with 200 records, and another kicked off with just one record. As soon as you execute a second job, you're going to error out. The simple fix is to keep your batch size low enough that you know evs will contain fewer than 200 records. A more robust fix is to add some logic to check if you should execute synchronously or asynhronously, and only use Queueable in the latter case.


Here's another use case one might encounter when getting this error

Given: Batch job execute() method that updates two records A and B

Given a Process Builder with two decision blocks / action group pairs that
execute upon changes to records A and B, respectively. 
That is decision block 1 applies to record A and decision block 2 applies to record B.

Given that the Process Builder action groups do either DML or call invocable apex.  
Underlying apex code then does a System.enqueueJob(...)

Although Process Builder is bulkified, it is not bulkified across action groups. Thus, even if the action groups invoke the same invocable method or DML the same SobjectType, you will end up with two separate System.enqueueJob calls.

Bottom line, code defensively before executing System.enqueueJob(..) as you might be surprised over time the context in which it is invoked. For example, in our use case, we had good unit tests that made sure that service X enqueued the job as expected; but no unit tests that checked to see if the service were called twice from a batchable context.