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
- Set config.backpressure to 'fallback-sync' (or 'wait' if available) to degrade gracefully instead of throwing.
- Raise the concurrency limit for the agent in manager config.
- Retry the enqueue with exponential backoff (the thrown error is retryable).
- 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
- Choose backpressure: 'fallback-sync' when rejection is unacceptable.
- Size the concurrency limit to real agent capacity.
- Retry enqueues with exponential backoff on limit errors.
- Monitor for tasks stuck in non-terminal states that hog slots.
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
- BackgroundTaskManager is shutting down, cannot enqueue new t
- Concurrency limit reached, cannot resume task "${taskId}" —
- Concurrency limit reached, cannot restart task "${taskId}" —
- MastraFactory.prepare() called twice
- Factory kickoff lease was lost before completion.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/8d8f4c4c49b6fef7.
Report an issue: GitHub.