ruvnet/ruflo · error
Worker ${this.id} at capacity (${maxTasks} tasks)
Error message
Worker ${this.id} at capacity (${maxTasks} tasks) What it means
WorkerBase.executeTask refuses work once currentTaskCount reaches config.maxConcurrentTasks (default 1). The check runs before the task starts; the counter is decremented when execution finishes, so the worker only accepts work below the cap — it does not queue.
Source
Thrown at v3/@claude-flow/integration/src/worker-base.ts:408
}
// ===== Task Execution =====
/**
* Execute a task with wrapper logic
*
* Handles load tracking, metrics, and error handling.
*
* @param task - Task to execute
* @returns Task result with metrics
*/
async executeTask(task: Task): Promise<TaskResult> {
this.ensureInitialized();
// Check capacity
const maxTasks = this.config.maxConcurrentTasks || 1;
if (this.currentTaskCount >= maxTasks) {
throw new Error(`Worker ${this.id} at capacity (${maxTasks} tasks)`);
}
this.currentTaskCount++;
this.updateLoad();
this.status = 'busy';
const startTime = Date.now();
this.emit('task-started', { workerId: this.id, taskId: task.id });
try {
// Execute via subclass implementation
const output = await this.execute(task);
const duration = Date.now() - startTime;
// Update metrics
this.updateMetricsSuccess(duration, output.tokensUsed);
View on GitHub (pinned to fa13ee4ad6)
Solutions
- Serialize per worker: await each executeTask before starting the next
- Raise config.maxConcurrentTasks — only if the subclass's execute() is actually safe to run concurrently
- Dispatch through a worker pool so busy workers are routed around instead of thrown on
Example fix
// before
await Promise.all([t1, t2].map(t => worker.executeTask(t))); // second call throws: cap is 1
// after
for (const t of [t1, t2]) {
await worker.executeTask(t); // serialized, stays under the cap
}
// or, when execute() is concurrency-safe:
new MyWorker({ id, maxConcurrentTasks: 4 }); Defensive patterns
Strategy: validation
Validate before calling
// Check the cap before dispatching; track occupancy via task events
const max = worker.config.maxConcurrentTasks ?? 1;
const busy = inFlightCount.get(worker.id) ?? 0; // increment on 'task-started', decrement on completion
if (busy >= max) {
await waitForWorkerIdle(worker.id); // or route to another worker
}
await worker.executeTask(task); Try / catch
try {
await worker.executeTask(task);
} catch (e) {
if (e instanceof Error && /at capacity/.test(e.message)) {
// backpressure: requeue the task or pick another worker; do not busy-retry
}
throw e;
} Prevention
- Serialize per-worker calls or route through a pool that skips busy workers
- Set maxConcurrentTasks deliberately, and only when execute() is reentrant-safe
- Watch 'task-started'/'task-completed' events to know real occupancy before dispatch
When it happens
Trigger: Dispatching a second concurrent task to a worker with maxConcurrentTasks unset (default 1) while the first is still running — e.g. Promise.all over the same worker instance.
Common situations: Assuming the worker queues internally (it throws instead); forgetting the default cap is 1; fanning out N tasks to one worker without raising the setting.
Related errors
- Agent ${this.id} has reached max concurrent tasks
- Bulkhead '${this.options.name}' is full. Max concurrent: ${t
- Agent at maximum concurrent task capacity
- Maximum tasks (${this.config.maxTasks}) reached
- Max sessions (${this.config.maxSessions}) reached
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/a0aed4849ce71985.
Report an issue: GitHub.