{"record":{"id":"e6ba8dc665eeafa8","repo":"can1357/oh-my-pi","slug":"tcp-port-host-port-was-not-ready-after-tim","errorCode":null,"errorMessage":"TCP port ${host}:${port} was not ready after ${timeoutMs}ms","messagePattern":"TCP port (.+?):(.+?) was not ready after (.+?)ms","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/dap/client.ts","lineNumber":860,"sourceCode":"/** Wait for a TCP DAP server and retain the first successful connection. */\nasync function waitForTcpTransport(\n\thost: string,\n\tport: number,\n\ttimeoutMs: number,\n\tproc: { exitCode: number | null },\n): Promise<SocketTransport> {\n\tconst deadline = Date.now() + timeoutMs;\n\twhile (Date.now() < deadline) {\n\t\tif (proc.exitCode !== null) {\n\t\t\tthrow new Error(`Adapter process exited before TCP port ${host}:${port} was ready`);\n\t\t}\n\t\ttry {\n\t\t\treturn await connectTcpSocket(host, port);\n\t\t} catch {\n\t\t\tawait Bun.sleep(50);\n\t\t}\n\t}\n\tthrow new Error(`TCP port ${host}:${port} was not ready after ${timeoutMs}ms`);\n}\n\n/**\n * Give the adapter a chance to announce it is listening on `port` before the\n * first connect. vscode-js-debug prints `Debug server listening at HOST:PORT`\n * to stdout from inside its `listen()` callback; waiting for the port to appear\n * there means we only connect once the child genuinely owns the reserved port,\n * which closes the WSL2-mirrored ghost-accept window (issue #6055) at its root.\n *\n * Best-effort: resolves on the banner, on process exit, or on timeout — the\n * subsequent connect loop and `proc.exitCode` checks surface real failures, so\n * an adapter that never prints a banner still proceeds (just without the gate).\n * Also drains stdout for the wait's duration: in tcp mode the DAP protocol\n * flows over the socket, so nothing else consumes the adapter's stdout.\n *\n * Exported so tests can drive the gate deterministically with a synthetic stdout.\n */\nexport async function waitForTcpServerListening(","sourceCodeStart":842,"sourceCodeEnd":878,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/dap/client.ts#L842-L878","documentation":"The TCP connect loop could not establish a connection to the adapter's listening port within timeoutMs. Unlike the exit-based error, the adapter process is still running — it just never accepted a TCP connection in time. This prevents indefinite hangs when an adapter never starts listening.","triggerScenarios":"Adapter runs but never calls listen() on the configured port within timeoutMs; connecting to the wrong host/port so every connectTcpSocket attempt fails; firewall or network namespace blocking 127.0.0.1:port; adapter listening on a different interface than probed.","commonSituations":"vscode-js-debug or debugpy slow to print/listen under load exceeding the timeout; host/port mismatch between adapter config and launcher; Docker/WSL setups where the port isn't reachable at 127.0.0.1; stale port from a previous crashed run.","solutions":["Increase timeoutMs for the TCP connect wait in the launch/connect call","Verify host and port match what the adapter actually announces on stdout (e.g. 'Debug server listening at ...')","Check the adapter is listening: ss/netstat/lsof on the configured port","Fix network/firewall configuration if the adapter runs in another namespace/container"],"exampleFix":"// before\nawait connectTcpPort(adapter, '127.0.0.1', 9229, 3000, proc);\n// after\nawait connectTcpPort(adapter, '127.0.0.1', 9229, 30_000, proc); // adapter needs longer to listen","handlingStrategy":"retry","validationCode":"const open = await Bun.$`lsof -i :${port}`.quiet().nothrow();\n// if adapter announced a port on stdout, use that instead of the configured guess","typeGuard":null,"tryCatchPattern":"try {\n  return await connectTcpPort(adapter, host, port, timeoutMs, proc);\n} catch (err) {\n  if (String((err as Error).message).includes('was not ready')) {\n    // adapter alive but never listened: probe the announced port from stdout\n    const announced = parseAnnouncedPort(adapterStdout);\n    if (announced && announced !== port) return await connectTcpPort(adapter, host, announced, timeoutMs, proc);\n  }\n  throw err;\n}","preventionTips":["Wait for the adapter's stdout announcement ('Debug server listening at HOST:PORT') before the first connect","Increase timeoutMs for adapters with slow listen startup","Confirm host/port match (127.0.0.1 vs container/WSL addresses) in both config and launch","Check firewalls/network namespaces when adapters run outside the host netns"],"tags":["dap","tcp","timeout","network"],"backgroundTag":"connection-refused","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}