jestjs/jest · error · Error

Queue implementation returned processed task

Error message

Queue implementation returned processed task

What it means

Thrown by `Farm._process` (Farm.ts:123-125) when a task dequeued from the custom `_taskQueue` already has `task.request[1] === true`. That flag is the 'already dispatched' marker, set at Farm.ts:141 right before handing the task to the worker. A dequeue returning an already-processed task means the TaskQueue implementation is violating its contract (a dequeue must return only pending tasks).

Source

Thrown at packages/jest-worker/src/Farm.ts:124

    promise.UNSTABLE_onCustomMessage = addCustomMessageListener;

    return promise;
  }

  private _process(workerId: number): Farm {
    if (this._isLocked(workerId)) {
      return this;
    }

    const task = this._taskQueue.dequeue(workerId);

    if (!task) {
      return this;
    }

    if (task.request[1]) {
      throw new Error('Queue implementation returned processed task');
    }

    // Reference the task object outside so it won't be retained by onEnd,
    // and other properties of the task object, such as task.request can be
    // garbage collected.
    let taskOnEnd: OnEnd | null = task.onEnd;
    const onEnd: OnEnd = (error, result) => {
      if (taskOnEnd) {
        taskOnEnd(error, result);
      }
      taskOnEnd = null;

      this._unlock(workerId);
      this._process(workerId);
    };

    task.request[1] = true;

View on GitHub (pinned to f49721c78e)

Solutions

  1. In your custom `TaskQueue.dequeue(workerId)`, ensure each returned task is removed and never returned again.
  2. Match the `TaskQueue` interface exactly: `enqueue(task, workerId?)` and `dequeue(workerId)` that pops the next pending task for that worker.
  3. Test the queue standalone: enqueue N tasks, dequeue must yield each exactly once.
  4. If you don't need custom scheduling, drop the `taskQueue` option and use the default `FifoQueue`.

Example fix

// before: custom queue returns the same task twice
class BuggyPriorityQueue {
  dequeue() { return this.tasks[0]; } // never removes
}
// after
class PriorityQ {
  dequeue(workerId) { return this.tasks.shift() ?? null; }
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Contract-test a custom TaskQueue: each enqueued task dequeues exactly once
function assertQueueContract(Q) {
  const q = new Q();
  const t1 = { request: [0, false] };
  q.enqueue(t1);
  if (q.dequeue() !== t1) throw new Error('dequeue must return enqueued task');
  if (q.dequeue() != null) throw new Error('dequeue must not return processed task');
}

Type guard

const isTaskQueue = (q: any): boolean =>
  q != null && typeof q.enqueue === 'function' && typeof q.dequeue === 'function';

Prevention

When it happens

Trigger: Providing a custom `taskQueue` option to `jest-worker`'s `Worker` whose `dequeue(workerId)` returns a task that was previously dequeued and dispatched (i.e. the queue retains and reissues processed tasks). The stock `FifoQueue` never does this; only a third-party/custom queue can.

Common situations: Writing a priority/re-entrant queue and forgetting to remove a task from internal storage on `dequeue`; a queue that copies/mirrors tasks across worker buckets and returns duplicates; a queue shared across Farms where dequeue semantics differ from what Farm expects (one-task-per-dequeue, FIFO per worker).

Related errors


AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03). Data as JSON: /data/errors/eb6de3559a02edd9.json. Report an issue: GitHub.