mastra-ai/mastra · warning · Error

Concurrency limit reached, cannot enqueue task for tool "${t

Error message

Concurrency limit reached, cannot enqueue task for tool "${task.toolName}"

What it means

When the per-agent concurrency limit is reached and config.backpressure is 'reject', enqueue() throws, deletes the already-created task record, and refuses the task. This is deliberate backpressure: instead of queueing unboundedly, the caller is told the system is saturated.

Source

Thrown at packages/core/src/background-tasks/manager.ts:320

      this.registerTaskContext(task.id, context);
    }

    const storage = await this.getStorage();
    await storage.createTask(task);

    const canRun = await this.checkConcurrency(task.agentId);

    if (canRun) {
      await this.dispatch(task);
      return { task };
    }

    // Backpressure
    switch (this.config.backpressure) {
      case 'reject':
        this.deregisterTaskContext(task.id);
        await storage.deleteTask(task.id);
        throw new Error(`Concurrency limit reached, cannot enqueue task for tool "${task.toolName}"`);

      case 'fallback-sync':
        this.deregisterTaskContext(task.id);
        await storage.deleteTask(task.id);
        return { task, fallbackToSync: true };

      case 'queue':
      default:
        // Task stays pending in storage, will be dispatched when a slot opens
        return { task };
    }
  }

  async cancel(taskId: string): Promise<void> {
    if (this.initPromise) await this.initPromise;
    const storage = await this.getStorage();
    let task = await storage.getTask(taskId);
    if (!task) {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Set config.backpressure to 'fallback-sync' (or 'wait' if available) to degrade gracefully instead of throwing.
  2. Raise the concurrency limit for the agent in manager config.
  3. Retry the enqueue with exponential backoff (the thrown error is retryable).
  4. Audit for leaked slots: tasks stuck in non-terminal states; cancel or complete them to free capacity.

Example fix

// before
const manager = new BackgroundTaskManager({ backpressure: 'reject', concurrency: 2 });
// after
const manager = new BackgroundTaskManager({ backpressure: 'fallback-sync', concurrency: 8 });
// or wrap enqueue in retry:
try { await manager.enqueue(p); } catch (e) { await sleep(backoff); retry(); }
Defensive patterns

Strategy: retry

Validate before calling

const inflight = await countInflightTasks(agentId); // e.g. storage listTasks filtered
if (inflight >= concurrencyLimit) await waitForSlot();

Try / catch

try {
  return await manager.enqueue(payload);
} catch (e) {
  if ((e as Error).message.startsWith('Concurrency limit reached')) {
    await sleep(backoffMs);
    return manager.enqueue(payload); // retry with backoff
  }
  throw e;
}

Prevention

When it happens

Trigger: Enqueueing more concurrent tasks for the same agentId than the configured concurrency limit with backpressure: 'reject'; bursts of parallel tool calls each creating background tasks; a stuck/suspended task occupying a concurrency slot.

Common situations: Fan-out agents spawning many background tool calls at once; misconfigured (too low) concurrency limit; tasks that never complete holding slots; load spikes during batch jobs.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/8d8f4c4c49b6fef7. Report an issue: GitHub.