{"record":{"id":"b954c21a88204eab","repo":"can1357/oh-my-pi","slug":"daemon-broker-socket-is-unavailable","errorCode":null,"errorMessage":"Daemon broker socket is unavailable","messagePattern":"Daemon broker socket is unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/launch/client.ts","lineNumber":168,"sourceCode":"\t#connectPromise: Promise<void> | undefined;\n\t#buffer = \"\";\n\t#closed = false;\n\t#completionReconnectTimer: NodeJS.Timeout | undefined;\n\n\tconstructor(projectDir: string, runtimeDir: string, token: string, options: DaemonBrokerClientOptions) {\n\t\tthis.projectDir = projectDir;\n\t\tthis.#runtimeDir = runtimeDir;\n\t\tthis.#endpoint = daemonBrokerEndpoint(projectDir, runtimeDir);\n\t\tthis.#token = token;\n\t\tthis.#idleGraceMs = options.idleGraceMs;\n\t}\n\n\tasync request(operation: DaemonOperation, signal?: AbortSignal): Promise<DaemonRpcResult> {\n\t\tif (this.#closed) throw new Error(\"Daemon broker client is closed\");\n\t\tif (signal?.aborted) throw new Error(\"Daemon broker request aborted\");\n\t\tawait this.#connect();\n\t\tconst socket = this.#socket;\n\t\tif (!socket || socket.destroyed) throw new Error(\"Daemon broker socket is unavailable\");\n\n\t\tconst completionUnsubscribes = [...this.#completionUnsubscribes];\n\t\tconst completionReplays = [...this.#completionReplays];\n\t\tconst id = crypto.randomUUID();\n\t\tconst { promise, resolve, reject } = Promise.withResolvers<DaemonRpcResult>();\n\t\tconst timer = setTimeout(() => {\n\t\t\tconst pending = this.#pending.get(id);\n\t\t\tif (!pending) return;\n\t\t\tthis.#pending.delete(id);\n\t\t\tpending.removeAbort?.();\n\t\t\treject(new Error(`Daemon ${operation.op} request timed out`));\n\t\t}, requestTimeoutMs(operation));\n\t\tconst pending: PendingRequest = { operation, resolve, reject, timer };\n\t\tif (signal) {\n\t\t\tconst abort = (): void => {\n\t\t\t\tif (!this.#pending.delete(id)) return;\n\t\t\t\tclearTimeout(timer);\n\t\t\t\treject(new Error(\"Daemon broker request aborted\"));","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/launch/client.ts#L150-L186","documentation":"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.","triggerScenarios":"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.","commonSituations":"Broker shutting down due to idle grace expiry; race between connect and broker restart; network/unix-socket interruption in long-running sessions.","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"],"exampleFix":"// before\nawait client.request(op);\n// after\ntry { await client.request(op); }\ncatch (err) {\n  if (String(err).includes(\"socket is unavailable\")) await client.request(op); // reconnect-retry\n  else throw err;\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"let lastErr: unknown;\nfor (let i = 0; i < 3; i++) {\n  try { return await client.request(op); }\n  catch (err) {\n    if (!String(err).includes('socket is unavailable')) throw err;\n    lastErr = err;\n    await Bun.sleep(50 * (i + 1));\n  }\n}\nthrow lastErr;","preventionTips":["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"],"tags":["ipc","socket","daemon","race-condition"],"backgroundTag":"socket-unavailable","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}