can1357/oh-my-pi · error · Error

TCP port ${host}:${port} was not ready after ${timeoutMs}ms

Error message

TCP port ${host}:${port} was not ready after ${timeoutMs}ms

What it means

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.

Source

Thrown at packages/coding-agent/src/dap/client.ts:860

/** Wait for a TCP DAP server and retain the first successful connection. */
async function waitForTcpTransport(
	host: string,
	port: number,
	timeoutMs: number,
	proc: { exitCode: number | null },
): Promise<SocketTransport> {
	const deadline = Date.now() + timeoutMs;
	while (Date.now() < deadline) {
		if (proc.exitCode !== null) {
			throw new Error(`Adapter process exited before TCP port ${host}:${port} was ready`);
		}
		try {
			return await connectTcpSocket(host, port);
		} catch {
			await Bun.sleep(50);
		}
	}
	throw new Error(`TCP port ${host}:${port} was not ready after ${timeoutMs}ms`);
}

/**
 * Give the adapter a chance to announce it is listening on `port` before the
 * first connect. vscode-js-debug prints `Debug server listening at HOST:PORT`
 * to stdout from inside its `listen()` callback; waiting for the port to appear
 * there means we only connect once the child genuinely owns the reserved port,
 * which closes the WSL2-mirrored ghost-accept window (issue #6055) at its root.
 *
 * Best-effort: resolves on the banner, on process exit, or on timeout — the
 * subsequent connect loop and `proc.exitCode` checks surface real failures, so
 * an adapter that never prints a banner still proceeds (just without the gate).
 * Also drains stdout for the wait's duration: in tcp mode the DAP protocol
 * flows over the socket, so nothing else consumes the adapter's stdout.
 *
 * Exported so tests can drive the gate deterministically with a synthetic stdout.
 */
export async function waitForTcpServerListening(

View on GitHub (pinned to 9690622007)

Solutions

  1. Increase timeoutMs for the TCP connect wait in the launch/connect call
  2. Verify host and port match what the adapter actually announces on stdout (e.g. 'Debug server listening at ...')
  3. Check the adapter is listening: ss/netstat/lsof on the configured port
  4. Fix network/firewall configuration if the adapter runs in another namespace/container

Example fix

// before
await connectTcpPort(adapter, '127.0.0.1', 9229, 3000, proc);
// after
await connectTcpPort(adapter, '127.0.0.1', 9229, 30_000, proc); // adapter needs longer to listen
Defensive patterns

Strategy: retry

Validate before calling

const open = await Bun.$`lsof -i :${port}`.quiet().nothrow();
// if adapter announced a port on stdout, use that instead of the configured guess

Try / catch

try {
  return await connectTcpPort(adapter, host, port, timeoutMs, proc);
} catch (err) {
  if (String((err as Error).message).includes('was not ready')) {
    // adapter alive but never listened: probe the announced port from stdout
    const announced = parseAnnouncedPort(adapterStdout);
    if (announced && announced !== port) return await connectTcpPort(adapter, host, announced, timeoutMs, proc);
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/e6ba8dc665eeafa8. Report an issue: GitHub.