can1357/oh-my-pi · error
${argv[0]} exited with code ${exitCode} before reporting a t
Error message
${argv[0]} exited with code ${exitCode} before reporting a tunnel URL What it means
spawnUrlTunnel launches a tunnel binary (cloudflared, ngrok, tailscale, etc.) and scans its stdout for a ready-marker URL. This error is thrown when the child process terminates with a non-zero (or any) exit code before ever printing a tunnel URL, so the broker cannot advertise a public base URL. It is the tunnel-binary crash path of the ready-wait loop.
Source
Thrown at packages/coding-agent/src/blob-broker/exposure.ts:279
if (text.length > scanned) {
if (baseUrl === undefined) {
for (const line of text.slice(scanned).split("\n")) {
const url = extract(line);
if (url) {
baseUrl = normalizeBaseUrl(url);
break;
}
}
scanned = text.lastIndexOf("\n") + 1;
}
// The URL banner can precede edge registration (cloudflared prints the
// hostname before any connection is live); wait for the ready marker.
if (baseUrl !== undefined && (!readyPattern || readyPattern.test(text))) {
return { proc, baseUrl };
}
}
if (exitCode !== null) {
throw new Error(`${argv[0]} exited with code ${exitCode} before reporting a tunnel URL`);
}
await Bun.sleep(150);
}
killTunnelProcess(proc);
throw new Error(`${argv[0]} did not report a tunnel URL within ${READY_TIMEOUT_MS / 1000}s`);
}
function processExposure(kind: ExposureKind, baseUrl: string, proc: Bun.Subprocess): ActiveExposure {
proc.unref();
return {
kind,
baseUrl,
exited: proc.exited.then(() => undefined),
stop: () => killTunnelProcess(proc),
};
}
/**View on GitHub (pinned to 9690622007)
Solutions
- Read the tunnel binary's stderr output from the spawn (it is captured but not in this error) and run the same argv manually to see the real failure.
- Verify credentials: ngrok authtoken, cloudflared tunnel token, bore secret.
- Confirm the binary runs: check version (`cloudflared --version`) and that CLI flags match the installed version.
- Check network egress/firewall allows the tunnel's outbound connection.
- Switch exposure kind (e.g. to `direct` on LAN) as a fallback.
Example fix
// before
options: { authtoken: "<old-expired-token>" }
// after
// refresh the token in ngrok dashboard, then
options: { authtoken: process.env.NGROK_AUTHTOKEN } Defensive patterns
Strategy: validation
Validate before calling
const probe = Bun.spawnSync([binary, "--version"], { stderr: "pipe" });
if (probe.exitCode !== 0) throw new Error(`tunnel binary ${binary} not runnable: ${probe.stderr.toString()}`); Try / catch
try {
const exposure = await startExposure(config);
} catch (err) {
if (err instanceof Error && err.message.includes("exited with code")) {
logger.warn("tunnel exited before ready; falling back", { kind: config.kind });
// inspect tunnel stderr or fall back to another exposure kind
} else throw err;
} Prevention
- Verify the tunnel binary exists and runs (--version) before startExposure
- Pre-authenticate the binary (ngrok authtoken, cloudflared login, tailscale up)
- Confirm outbound network egress from the host
- Pin/verify binary version so CLI flags match
When it happens
Trigger: Calling startExposure with a tunnel kind (cloudflared/ngrok/bore/pinggy/devtunnel/zrok/localhost-run) whose binary exits during the 30s READY_TIMEOUT_MS window before emitting a parseable tunnel URL line — e.g. bad auth token, port conflict, invalid flags, or the binary crashes on startup.
Common situations: Expired or wrong ngrok authtoken; cloudflared quick-tunnel blocked by network egress rules; bore/zrok server unreachable so the client exits; binary version changed its CLI flags and dies immediately; sandboxed/container environments that cannot open outbound connections.
Related errors
- Exposure health probe for ${destination} failed with status
- ${argv[0]} did not report a tunnel URL within ${READY_TIMEOU
- ssh reverse forward to ${config.sshTarget} exited with code
- ssh exited with code ${exitCode}
- cli_message(command, exit_code, stdout, stderr)
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/d672ce00e4569062.
Report an issue: GitHub.