{"record":{"id":"1e12f6a3f4876faf","repo":"can1357/oh-my-pi","slug":"adapter-process-exited-before-socket-was-ready","errorCode":null,"errorMessage":"Adapter process exited before socket was ready","messagePattern":"Adapter process exited before socket was ready","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/dap/client.ts","lineNumber":779,"sourceCode":"\ttry {\n\t\treturn (await fs.stat(socketPath)).isSocket();\n\t} catch (error) {\n\t\tif (isEnoent(error)) return false;\n\t\tthrow error;\n\t}\n}\n\n/** Poll a condition until it returns true, or timeout/process exit. */\nasync function waitForCondition(\n\tcheck: () => boolean | Promise<boolean>,\n\ttimeoutMs: number,\n\tproc: { exitCode: number | null },\n): Promise<void> {\n\tconst deadline = Date.now() + timeoutMs;\n\twhile (Date.now() < deadline) {\n\t\tif (await check()) return;\n\t\tif (proc.exitCode !== null) {\n\t\t\tthrow new Error(\"Adapter process exited before socket was ready\");\n\t\t}\n\t\tawait Bun.sleep(50);\n\t}\n\tthrow new Error(`Socket not ready after ${timeoutMs}ms`);\n}\n\n/** Connect once to a TCP DAP server. */\nasync function connectTcpSocket(host: string, port: number, onClose?: () => void): Promise<SocketTransport> {\n\tconst { promise, resolve, reject } = Promise.withResolvers<SocketTransport>();\n\tlet streamController: ReadableStreamDefaultController<Uint8Array>;\n\tlet opened = false;\n\tconst readable = new ReadableStream<Uint8Array>({\n\t\tstart(controller) {\n\t\t\tstreamController = controller;\n\t\t},\n\t});\n\n\tvoid Bun.connect({","sourceCodeStart":761,"sourceCodeEnd":797,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/dap/client.ts#L761-L797","documentation":"When launching a socket-based (stdio pipe or TCP) DAP adapter, the client waits for a readiness check (e.g. socket/port availability) before use. If the adapter process exits (non-null exitCode) before that check succeeds, this error is thrown because the process will never become ready. It distinguishes 'not ready yet' from 'adapter died at startup'.","triggerScenarios":"The adapter executable crashes immediately after launch (bad interpreter, missing module, invalid config passed via launch args); the launch command errors out before opening its socket; the adapter exits during the startup window while waitFor readiness is polling.","commonSituations":"Wrong adapter path or runtime in debug config (e.g. node version without required flags); a Python debugpy entrypoint typo'd so the process dies; adapter killed by missing environment variables or unresolvable cwd; port configured but adapter fails to bind and exits.","solutions":["Run the adapter command manually with the same args/cwd to see its startup error output","Fix the adapter path, runtime, and launch configuration (program, cwd, env) in the resolved adapter config","Check the adapter's stderr/stdout logs for the crash reason; capture them at launch","Verify the adapter binary is executable and compatible with the platform (e.g. correct arch)"],"exampleFix":"// before\nadapter: { command: 'node', args: ['--inspect', 'dbg.js'] } // crashes on old node\n// after\nadapter: { command: 'node', args: ['--loader', './dap-loader.mjs', 'dbg.js'] } // verify with: node --loader ./dap-loader.mjs dbg.js","handlingStrategy":"validation","validationCode":"const proc = Bun.spawn([adapter.command, ...adapter.args], { cwd, stderr: 'pipe' });\n// surface early failure before waiting for readiness\nproc.exited.then(code => { if (code !== 0) console.error(await new Response(proc.stderr).text()); });","typeGuard":null,"tryCatchPattern":"try {\n  await DapClient.connect({ adapter, cwd, timeoutMs: 10_000 });\n} catch (err) {\n  if (String((err as Error).message).includes('exited before')) {\n    console.error('adapter startup failed; check adapter path/args and stderr logs');\n  }\n  throw err;\n}","preventionTips":["Validate the adapter command exists and is executable before launch ($which)","Smoke-test the adapter command line manually with the exact args/cwd from config","Capture and log adapter stdout/stderr at launch so startup crashes are diagnosable","Pin adapter/runtime versions to known-working combinations"],"tags":["dap","startup","process-exit","debug-adapter"],"backgroundTag":"adapter-crashed-on-startup","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}