n8n-io/n8n · error · Error
Run timed out after ${String(config.timeoutMs)}ms
Error message
Run timed out after ${String(config.timeoutMs)}ms What it means
Thrown in the run-resumed loop of the chat driver after a run-finish, when the main agent has started a NEW run (run-start count exceeds run-finish count) and the total elapsed time since config.startTime has exceeded config.timeoutMs. Before throwing, the run is cancelled via client.cancelRun (errors swallowed). This guards the 'agent resumed itself' branch so a self-perpetuating loop cannot run forever.
Source
Thrown at packages/@n8n/instance-ai/evaluations/harness/chat-loop.ts:146
// Wait for observational-memory jobs (observer/reflector) before the next user turn
await waitForMemoryTasks(config);
// Check if the main agent started a new run after background tasks completed
await delay(SSE_SETTLE_DELAY_MS);
const newRunStarts = countEvents(config.events, 'run-start');
const currentRunFinishes = countEvents(config.events, 'run-finish');
if (newRunStarts <= currentRunFinishes) {
break;
}
config.logger.verbose(
`[${config.threadId}] Main agent resumed (run-start #${String(newRunStarts)}) -- waiting for completion`,
);
if (Date.now() - config.startTime > config.timeoutMs) {
await config.client.cancelRun(config.threadId).catch(() => {});
throw new Error(`Run timed out after ${String(config.timeoutMs)}ms`);
}
}
}
async function waitForRunFinish(config: WaitConfig, expectedFinishCount: number): Promise<void> {
while (countEvents(config.events, 'run-finish') <= expectedFinishCount) {
const elapsed = Date.now() - config.startTime;
if (elapsed > config.timeoutMs) {
await config.client.cancelRun(config.threadId).catch(() => {});
throw new Error(`Run timed out after ${String(config.timeoutMs)}ms`);
}
await processConfirmationRequests(config);
await delay(POLL_INTERVAL_MS);
}
}
async function waitForBackgroundTasks(config: WaitConfig, timeoutMs: number): Promise<void> {View on GitHub (pinned to 5ac6606e81)
Solutions
- Raise config.timeoutMs for the case if the run legitimately needs more time.
- Investigate why the agent resumes (new run-start) repeatedly — a tool loop or repeated confirmation requests.
- If transient, re-run the case; persistent timeouts indicate an agent-behavior or backend-liveness problem.
Defensive patterns
Strategy: try-catch
Validate before calling
// Budget check before resuming — surface a clear reason instead of a raw timeout.
if (Date.now() - config.startTime > config.timeoutMs) {
throw new Error(`Aborting before resume: elapsed ${Date.now() - config.startTime}ms exceeds budget ${config.timeoutMs}ms; raise config.timeoutMs or investigate the resume loop.`);
} Try / catch
// Treat timeout as a recoverable eval failure, not a crash.
try {
await driveChatLoop(config);
} catch (e) {
if (e instanceof Error && /Run timed out after/.test(e.message)) {
recordCaseTimeout(config.threadId, config.timeoutMs);
}
throw e;
} Prevention
- Size config.timeoutMs to the case's expected turn count and tool latency.
- Investigate repeated resume cycles (run-start > run-finish) as an agent tool-loop bug.
- Log resume counts so a slow drift toward the budget is visible before it trips.
When it happens
Trigger: A multi-turn case where the agent keeps starting new runs (e.g. it loops on a tool, or background tasks trigger follow-up runs) such that the wall-clock budget runs out while the loop waits for the resumed run.
Common situations: An agent caught in a tool-call loop; an overly generous timeoutMs still exceeded by a pathological case; slow LLM responses across many resume cycles.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Database connection timed out
- Timed out after ${timeoutMs}ms waiting for database connecti
- Expression timed out after ${this.config.timeout}ms
- Not authenticated — call login() first
- SSE connection failed (${res.status}): ${text}
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/aa3452da854561b5.
Report an issue: GitHub.