can1357/oh-my-pi · critical
Failed to start daemon broker: ${lastError?.message ?? "sock
Error message
Failed to start daemon broker: ${lastError?.message ?? "socket unavailable"} What it means
#connectOnce attempts to connect to the broker socket and, if unreachable, spawns the broker and retries within a deadline. When all attempts fail, it throws this aggregate error carrying the last underlying failure's message (or 'socket unavailable' if none was captured).
Source
Thrown at packages/coding-agent/src/launch/client.ts:305
this.#bindSocket(await openSocket(this.#endpoint, 250));
return;
} catch {
// No live broker. Multiple clients may race to spawn; the broker's PID
// lease selects one winner before any candidate touches the socket.
}
this.#spawnBroker();
const deadline = Date.now() + CONNECT_TIMEOUT_MS;
let lastError: Error | undefined;
while (Date.now() < deadline) {
try {
this.#bindSocket(await openSocket(this.#endpoint, 250));
return;
} catch (error) {
lastError = error instanceof Error ? error : new Error(String(error));
await Bun.sleep(CONNECT_RETRY_MS);
}
}
throw new Error(`Failed to start daemon broker: ${lastError?.message ?? "socket unavailable"}`);
}
#spawnBroker(): void {
const spawn = resolveWorkerSpawnCmd(DAEMON_BROKER_WORKER_ARG);
const overlay: Record<string, string> = {
[DAEMON_PROJECT_DIR_ENV]: this.projectDir,
[DAEMON_RUNTIME_DIR_ENV]: this.#runtimeDir,
};
if (this.#idleGraceMs !== undefined) overlay[DAEMON_IDLE_GRACE_ENV] = String(this.#idleGraceMs);
const child = Bun.spawn(spawn.cmd, {
cwd: spawn.cwd,
env: workerEnvFromParent(overlay),
stdin: "ignore",
stdout: "ignore",
stderr: "ignore",
...BROKER_SPAWN_OPTIONS,
});
child.unref();View on GitHub (pinned to 9690622007)
Solutions
- Read lastError in the message — fix the underlying broker startup failure first
- Verify the runtime dir is writable and the worker entry resolves (workerHostEntry / fallback)
- Run the broker in the foreground to see its real startup error, then retry the client
Example fix
// before
await client.request(op); // throws aggregate start failure
// after
try { await client.request(op); }
catch (err) {
logger.error("daemon broker start failed", { cause: err.message }); // inspect lastError, fix root cause
throw err;
} Defensive patterns
Strategy: retry
Validate before calling
const socketPath = daemonBrokerEndpoint(projectDir, runtimeDir);
await fs.mkdir(runtimeDir, { recursive: true });
await fs.access(runtimeDir, fs.constants.W_OK); // runtime dir must be writable before connecting Try / catch
try {
await client.request({ op: 'ping' });
} catch (err) {
if (err.message.startsWith('Failed to start daemon broker')) {
logger.error('broker start failed', { cause: err.message }); // message embeds lastError — fix root cause
}
throw err;
} Prevention
- Verify runtimeDir is on a filesystem supporting unix sockets (not some network mounts)
- Ensure the worker host entry resolves before spawning
- Run the broker manually once to observe its real startup error
When it happens
Trigger: Broker repeatedly fails to start (bad env, missing worker entry, crash loop) or the socket path is unusable, exhausting the connect deadline.
Common situations: Runtime dir on a filesystem without unix socket support; broker worker crashing at startup (see env/token errors); permission issues on the socket file; port/path collisions between projects.
Related errors
- blob daemon ${input} responded ${response.status}
- blob broker exposure failed to start
- Daemon broker authentication failed
- Daemon ${operation.name} is ${record.snapshot.state}
- Daemon broker environment is incomplete
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/fec571f43f55cc91.
Report an issue: GitHub.