can1357/oh-my-pi · error · Error

Port ${host}:${chosen} is already in use; cannot start remot

Error message

Port ${host}:${chosen} is already in use; cannot start remote debugger there.

What it means

startRemoteDebugger/launch refuses to bind its remote-debugger server when the chosen port already accepts connections. It probes the port first because a plain bind error would be ambiguous and a success probe might connect to an unrelated service already listening there.

Source

Thrown at packages/coding-agent/src/debug/remote-debugger.ts:123

export async function startRemoteDebuggerServer(options: StartRemoteDebuggerOptions = {}): Promise<RemoteDebuggerInfo> {
	if (active) return active;
	starting ??= launch(options);
	try {
		return await starting;
	} finally {
		starting = null;
	}
}

async function launch({ port, start = startRemoteDebugger }: StartRemoteDebuggerOptions): Promise<RemoteDebuggerInfo> {
	const host = DEFAULT_HOST;
	const chosen = port ?? (await reserveFreePort(host));

	// Something already on this port? Refuse up front: otherwise Bun throws a
	// real bind error and our success probe would connect to that unrelated
	// service, marking a bogus endpoint as the debugger.
	if (await tryConnect(host, chosen, PROBE_INTERVAL_MS)) {
		throw new Error(`Port ${host}:${chosen} is already in use; cannot start remote debugger there.`);
	}

	let thrown: unknown;
	try {
		start(host, chosen);
	} catch (err) {
		// Bun's startRemoteDebugger throws a spurious bind error even on success,
		// so defer the verdict to the loopback probe below.
		thrown = err;
	}

	if (await waitForListening(host, chosen)) {
		active = { host, port: chosen };
		return active;
	}

	throw thrown instanceof Error ? thrown : new Error(`Remote debugger socket never came up on ${host}:${chosen}`);
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Omit the `port` argument so a free port is reserved automatically
  2. Find and stop the process occupying the port (e.g. `lsof -i :<port>` / `ss -ltnp`)
  3. Choose a different port in your configuration
  4. Retry after a delay if the conflict was transient (another instance shutting down)

Example fix

// before
const dbg = await startRemoteDebuggerServer({ host: '127.0.0.1', port: 9229 });
// after
const dbg = await startRemoteDebuggerServer({ host: '127.0.0.1' }); // picks a free port
Defensive patterns

Strategy: validation

Validate before calling

import { tryConnect } from './remote-debugger';
if (await tryConnect(host, port, 100)) {
	throw new SkipOperation(`port ${host}:${port} occupied`);
}

Try / catch

try {
	const dbg = await startRemoteDebuggerServer({ host, port });
} catch (err) {
	if (err.message.includes('already in use')) {
		dbg = await startRemoteDebuggerServer({ host }); // let it pick a free port
	}
}

Prevention

When it happens

Trigger: Calling launch/startRemoteDebuggerServer with an explicit `port` that another process is listening on, or when `reserveFreePort(host)` returned a port that got claimed between reservation and bind (TOCTOU), on the given host.

Common situations: Two omp/debugger instances started concurrently; a stale debugger server from a crashed previous run still holding the port; another dev service occupying the port; hardcoded port in config colliding across team members or containers.

Related errors


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