can1357/oh-my-pi · error
Daemon broker socket is unavailable
Error message
Daemon broker socket is unavailable
What it means
After #connect() resolves, request() double-checks that the socket exists and is not destroyed. If #connect failed to leave a healthy socket (connection dropped between connect and use), this error is thrown as a defensive guard.
Source
Thrown at packages/coding-agent/src/launch/client.ts:168
#connectPromise: Promise<void> | undefined;
#buffer = "";
#closed = false;
#completionReconnectTimer: NodeJS.Timeout | undefined;
constructor(projectDir: string, runtimeDir: string, token: string, options: DaemonBrokerClientOptions) {
this.projectDir = projectDir;
this.#runtimeDir = runtimeDir;
this.#endpoint = daemonBrokerEndpoint(projectDir, runtimeDir);
this.#token = token;
this.#idleGraceMs = options.idleGraceMs;
}
async request(operation: DaemonOperation, signal?: AbortSignal): Promise<DaemonRpcResult> {
if (this.#closed) throw new Error("Daemon broker client is closed");
if (signal?.aborted) throw new Error("Daemon broker request aborted");
await this.#connect();
const socket = this.#socket;
if (!socket || socket.destroyed) throw new Error("Daemon broker socket is unavailable");
const completionUnsubscribes = [...this.#completionUnsubscribes];
const completionReplays = [...this.#completionReplays];
const id = crypto.randomUUID();
const { promise, resolve, reject } = Promise.withResolvers<DaemonRpcResult>();
const timer = setTimeout(() => {
const pending = this.#pending.get(id);
if (!pending) return;
this.#pending.delete(id);
pending.removeAbort?.();
reject(new Error(`Daemon ${operation.op} request timed out`));
}, requestTimeoutMs(operation));
const pending: PendingRequest = { operation, resolve, reject, timer };
if (signal) {
const abort = (): void => {
if (!this.#pending.delete(id)) return;
clearTimeout(timer);
reject(new Error("Daemon broker request aborted"));View on GitHub (pinned to 9690622007)
Solutions
- Retry the request — reconnect is usually sufficient since #connect re-establishes the socket
- Check broker liveness (ping/start operation) and restart the broker if dead
- Increase DAEMON_IDLE_GRACE_ENV if the broker is idling out during bursts of requests
Example fix
// before
await client.request(op);
// after
try { await client.request(op); }
catch (err) {
if (String(err).includes("socket is unavailable")) await client.request(op); // reconnect-retry
else throw err;
} Defensive patterns
Strategy: retry
Try / catch
let lastErr: unknown;
for (let i = 0; i < 3; i++) {
try { return await client.request(op); }
catch (err) {
if (!String(err).includes('socket is unavailable')) throw err;
lastErr = err;
await Bun.sleep(50 * (i + 1));
}
}
throw lastErr; Prevention
- Keep the broker alive: tune DAEMON_IDLE_GRACE_ENV above your burst gaps
- Probe broker liveness before long request sequences
- Handle broker restarts by reconnecting transparently
When it happens
Trigger: The broker socket closed during #connect (broker exiting, idle shutdown, socket error) so this.#socket is null or .destroyed by the time request() reads it.
Common situations: Broker shutting down due to idle grace expiry; race between connect and broker restart; network/unix-socket interruption in long-running sessions.
Related errors
- blob daemon ${input} responded ${response.status}
- blob broker exposure failed to start
- Daemon broker authentication failed
- Daemon ${spec.name} is already starting
- Daemon ${operation.name} is ${record.snapshot.state}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/b954c21a88204eab.
Report an issue: GitHub.