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
- Read the ssh diagnostics printed before the error and fix the specific failure (host, key, network).
- Free the local callback port if already bound (`lsof -i :<port>`, then stop the holder).
- 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
- Test `ssh <host>` manually before scripted remote logins.
- Free the forwarded callback port (`lsof -i :<port>`) before re-running.
- Use `ssh -o BatchMode=yes` checks in CI to fail fast on auth issues.
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
- ssh reverse forward to ${config.sshTarget} exited with code
- ${argv[0]} exited with code ${exitCode} before reporting a t
- Failed to start SSH master for ${target}${detail}
- cli_message(command, exit_code, stdout, stderr)
- timed out: {command}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e5d419c43d1848c6.
Report an issue: GitHub.