can1357/oh-my-pi · error

ssh exited with code ${exitCode}

Error message

ssh exited with code ${exitCode}

What it means

After spawning `ssh` with inherited stdio to establish the OAuth port-forward, `runRemoteLogin` awaits the process exit code and throws if it is non-zero. Any ssh failure (auth rejection, unreachable host, port bind conflict) is reported with the raw exit code, preserving the ssh diagnostics printed to the terminal.

Source

Thrown at packages/coding-agent/src/cli/auth-broker-cli.ts:404

		`${APP_NAME} auth-broker login ${provider}`,
	];
	if (dryRun) {
		process.stdout.write(`ssh ${sshArgs.map(a => (a.includes(" ") ? `'${a}'` : a)).join(" ")}\n`);
		return;
	}
	const sshBin = $which("ssh");
	if (!sshBin) {
		throw new Error("ssh binary not found in PATH");
	}
	const proc = Bun.spawn({
		cmd: [sshBin, ...sshArgs],
		stdin: "inherit",
		stdout: "inherit",
		stderr: "inherit",
	});
	const exitCode = await proc.exited;
	if (exitCode !== 0) {
		throw new Error(`ssh exited with code ${exitCode}`);
	}
}

async function runLogout(flags: AuthBrokerCommandArgs["flags"]): Promise<void> {
	let providerArg = flags.provider;
	const store = await SqliteAuthCredentialStore.open(getAgentDbPath());
	try {
		if (!providerArg) {
			const stored = store.listProviders();
			if (stored.length === 0) {
				process.stdout.write("No credentials stored.\n");
				return;
			}
			providerArg = await pickStoredProviderInteractively(stored);
		}
		store.deleteAuthCredentialsForProvider(providerArg, "logged out by user");
		process.stdout.write(`Logged out of ${providerArg}\n`);
	} finally {

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the ssh diagnostics printed before the error and fix the specific failure (host, key, network).
  2. Free the local callback port if already bound (`lsof -i :<port>`, then stop the holder).
  3. Verify connectivity manually (`ssh <host> true`), resolve auth/host-key prompts, then re-run the login.

Example fix

// before
omp auth-broker login --via bastion   // ssh exited with code 255
// after (verify ssh first)
ssh bastion true && omp auth-broker login --via bastion
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: ssh connectivity and free local port
await $`ssh -o BatchMode=yes ${host} true`.quiet().nothrow();
const port = CALLBACK_PORTS[provider];
const inUse = await $`lsof -i :${port}`.quiet().nothrow();
if (inUse.exitCode === 0) console.warn(`port ${port} already bound; stop the holder first`);

Try / catch

try {
  await runLogin({ provider, via: host });
} catch (err) {
  if (err instanceof Error && err.message.startsWith("ssh exited with code ")) {
    const code = Number(err.message.match(/code (\d+)/)?.[1]);
    // 255 = ssh error (auth/host); see ssh(1) for other codes
    console.error(`ssh failed (exit ${code}); fix host/key/port conflict and retry.`);
  } else throw err;
}

Prevention

When it happens

Trigger: ssh exits non-zero during remote login: wrong host/user, key rejected or agent missing, local callback port already bound (`Address already in use`), host key verification failure, or network timeout.

Common situations: Another local process holding the forwarded port; stale `known_hosts` after server rebuild; expired SSH key/agent not running; typo in the `--via host` argument.

Related errors


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