n8n-io/n8n · error · Error
toolCallConcurrency must be a positive integer or Infinity
Error message
toolCallConcurrency must be a positive integer or Infinity
What it means
Thrown by Agent.toolCallConcurrency(n) when n is not a positive integer and not Infinity. The check rejects zero, negative numbers, fractional numbers, NaN, and non-integer values. This controls how many tool calls within a single LLM turn execute in parallel, so it must be a valid positive count.
Source
Thrown at packages/@n8n/agents/src/sdk/agent.ts:548
}
return this;
}
/** @internal Read the declared telemetry builder (used by the execution engine to resolve credentials). */
protected get declaredTelemetry(): Telemetry | undefined {
return this.telemetryBuilder;
}
/**
* Set the number of tool calls to execute concurrently within a single LLM turn.
*
* - `1` (default) — sequential execution, fully backward-compatible.
* - `Infinity` — unlimited parallelism (all tool calls start at once).
* - Any number in between — bounded concurrency (e.g. `5` = at most 5 tools run simultaneously).
*/
toolCallConcurrency(n: number): this {
if ((n !== Infinity && !Number.isInteger(n)) || n < 1) {
throw new Error('toolCallConcurrency must be a positive integer or Infinity');
}
this.concurrencyValue = n;
return this;
}
/**
* Attach a workspace to this agent. Workspace tools and instructions
* are injected at build time.
*/
workspace(ws: Workspace): this {
this.workspaceInstance = ws;
return this;
}
/**
* Add an MCP client as a tool source for this agent.
* Tools from all servers in the client become available to the agent.
* Multiple clients can be added; tools are merged across all of them.View on GitHub (pinned to 5ac6606e81)
Solutions
- Pass 1 for sequential execution (the default), a positive integer for bounded concurrency, or Infinity for unlimited.
- If reading from config, validate and coerce: const n = parseInt(raw, 10); if (Number.isInteger(n) && n >= 1) agent.toolCallConcurrency(n).
- Use a fallback default of 1 when the config value is missing or invalid.
Example fix
// before const raw = process.env.TOOL_CONCURRENCY; // undefined or '0' agent.toolCallConcurrency(parseInt(raw)); // NaN or 0 -> throws // after const n = Number.parseInt(process.env.TOOL_CONCURRENCY ?? '1', 10); agent.toolCallConcurrency(Number.isFinite(n) && n >= 1 ? n : 1);
Defensive patterns
Strategy: validation
Validate before calling
function isValidConcurrency(n: unknown): boolean {
return n === Infinity || (typeof n === 'number' && Number.isInteger(n) && n >= 1);
}
const concurrency = isValidConcurrency(rawValue) ? (rawValue as number) : 1;
agent.toolCallConcurrency(concurrency); Type guard
function isPositiveIntegerOrInfinity(n: unknown): n is number {
return n === Infinity || (typeof n === 'number' && Number.isInteger(n) && n >= 1);
} Prevention
- Validate concurrency values from env vars or config files before passing them.
- Default to 1 when the source value is missing, NaN, or invalid.
- Use Number.isInteger() checks for config-derived integers.
When it happens
Trigger: Calling agent.toolCallConcurrency(0), toolCallConcurrency(-1), toolCallConcurrency(2.5), toolCallConcurrency(NaN), or passing a value from user input that was not validated as a positive integer.
Common situations: Reading concurrency from an environment variable or config file without parsing or validating (e.g. parseInt returning NaN for a missing value). Defaulting to 0 meaning 'disabled'. Passing a float from a slider or ratio calculation. Distinguishing 'sequential' (1) from 'off' (0) incorrectly.
Related errors
- Model ID is required
- Invalid delegate sub-agent tool name "${name}": must start w
- ${toolName} requires resumeSubAgent and cancelSubAgent to be
- Invalid memory configuration. Use: new Memory() for in-proce
- Agent "${this.name}" requires a model
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/0c1a6632e913f1d6.
Report an issue: GitHub.