n8n-io/n8n · error · Error
Daemon spawned (pid ${pid}) but did not pair within ${String
Error message
Daemon spawned (pid ${pid}) but did not pair within ${String(PAIRING_TIMEOUT_MS / 1000)}s. Check ${logPath} for errors. What it means
Thrown by `ensureDaemon()` after the daemon process was spawned (a pid was returned) but the gateway status poll never reported `connected` within `PAIRING_TIMEOUT_MS` (90s). The loop polls `client.getGatewayStatus()` every 500ms; if no successful pairing happens in 180 polls, the daemon is considered wedged. The message points at the daemon log file (`.eval-output/daemon.log`) which will contain the daemon's stdout/stderr and usually the real cause.
Source
Thrown at packages/@n8n/instance-ai/evaluations/computer-use/daemon.ts:124
usePublished,
logger,
});
logger.info(`Daemon spawned (pid ${pid}, log: ${logPath})`);
logger.info('Daemon will keep running after the eval exits — re-runs will reuse it.');
const deadline = Date.now() + PAIRING_TIMEOUT_MS;
while (Date.now() < deadline) {
await delay(PAIRING_POLL_INTERVAL_MS);
status = await client.getGatewayStatus();
if (status.connected && status.directory) {
logger.info(
`Daemon paired in ${String(Math.round((PAIRING_TIMEOUT_MS - (deadline - Date.now())) / 1000))}s`,
);
return toInfo(status);
}
}
throw new Error(
`Daemon spawned (pid ${pid}) but did not pair within ${String(PAIRING_TIMEOUT_MS / 1000)}s. ` +
`Check ${logPath} for errors.`,
);
}
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function toInfo(status: {
directory: string | null;
toolCategories: Array<{ name: string; enabled: boolean }>;
}): DaemonInfo {
return {
directory: status.directory ?? '',
enabledCategories: (status.toolCategories ?? []).filter((c) => c.enabled).map((c) => c.name),
};
}View on GitHub (pinned to 5ac6606e81)
Solutions
- Read `.eval-output/daemon.log` (the path in the error) — the daemon's own stderr will state why it didn't pair (port conflict, token error, missing browser, etc.).
- If the log shows a spawn failure or crash, rebuild `@n8n/computer-use` and `@n8n/mcp-browser` and try again.
- If the log shows the daemon is healthy but pairing never completes, check the browser extension is installed and n8n is reachable from the daemon's host; verify `--base-url` matches what the daemon was spawned with.
- If running on a chronically slow machine, you cannot raise the timeout from the CLI (PAIRING_TIMEOUT_MS is a constant); start the daemon manually beforehand so `ensureDaemon` reuses it instead of spawning.
- If a previous wedged daemon is still running, kill it (`pkill -f computer-use`) before re-running so the runner doesn't reuse a stuck process.
Defensive patterns
Strategy: try-catch
Try / catch
try {
const info = await ensureDaemon(opts);
} catch (e) {
if (e instanceof Error && /did not pair within/.test(e.message)) {
// read the daemon log for the real cause before retrying
const log = await readFile(join(opts.evalOutputDir, 'daemon.log'), 'utf-8');
throw new Error(`${e.message}\n--- daemon.log ---\n${log}`);
}
throw e;
} Prevention
- When iterating, start the daemon manually once so subsequent runs reuse it instead of re-spawning and re-pairing.
- On a slow machine, don't rely on auto-start; pre-pair the daemon.
- Always read `.eval-output/daemon.log` after a pairing timeout — the synchronous timeout message hides the asynchronous spawn error written to the log.
When it happens
Trigger: Daemon started but crashed immediately (the spawn-error handler appended `[daemon] spawn failed (...)` to the log but the process lingered long enough to report a pid). Daemon started but the pairing token was rejected by n8n (clock skew, mismatched baseUrl, expired link token). Daemon started but couldn't reach the browser extension / playwright, so it never reached 'connected'. Network/firewall blocking the daemon's loopback webhook back to n8n.
Common situations: First run on a machine where the browser extension isn't installed/connected. After changing `--base-url` such that the daemon can reach n8n but the browser side can't reach the daemon. After a Node version change that breaks a native dep in `@n8n/mcp-browser`. On a slow CI box where 90s isn't enough (rare — pairing is usually <10s).
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- No computer-use daemon is paired with this n8n instance. Ei
- Failed to spawn daemon: `${command}` did not start. See ${ar
- Local computer-use build not found at ${LOCAL_COMPUTER_USE_C
- Gateway rejected token: ${status} ${body}
- Failed to upload capabilities: ${response.status} ${text}
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/4e29569e865024aa.
Report an issue: GitHub.