Yeachan-Heo/oh-my-codex · error · Error
detached leader interrupted before release: ${interrupted}
Error message
detached leader interrupted before release: ${interrupted} What it means
While the leader polls for the launcher's release report, it also watches for SIGINT/SIGTERM/SIGHUP; receiving any of these before release aborts with the signal name.
Source
Thrown at src/cli/index.ts:7095
...record,
...(runtimeBinding ? {
tmux_internal_session_id: runtimeBinding.internalSessionId,
tmux_session_created: runtimeBinding.sessionCreated,
tmux_pane_pid: runtimeBinding.panePid,
} : {}),
});
if (payload.readyPath) {
writeDetachedLeaderReport(payload.readyPath, { version: 1, kind: "ready", nonce, sessionId: payload.sessionId, sessionName: payload.sessionName, paneId: pane, leaderPid: process.pid });
const releasePath = `${payload.readyPath}.release`;
const abortPath = `${payload.readyPath}.abort`;
const releaseDeadline = Date.now() + 30_000;
let interrupted: NodeJS.Signals | undefined;
const interrupt = (signal: NodeJS.Signals): void => { interrupted = signal; };
process.once("SIGINT", () => interrupt("SIGINT"));
process.once("SIGTERM", () => interrupt("SIGTERM"));
process.once("SIGHUP", () => interrupt("SIGHUP"));
while (true) {
if (interrupted) throw new Error(`detached leader interrupted before release: ${interrupted}`);
const release = readDetachedLeaderReport(releasePath);
if (release?.kind === "release" && release.nonce === nonce && release.sessionId === payload.sessionId && release.sessionName === payload.sessionName && release.leaderPid === process.pid) {
detachedHudProof = parseDetachedHudAuthorityProof(release.hud);
break;
}
const abort = readDetachedLeaderReport(abortPath);
if (abort?.kind === "abort" && abort.nonce === nonce && abort.sessionId === payload.sessionId && abort.sessionName === payload.sessionName && abort.leaderPid === process.pid) {
throw new Error("detached launch aborted before release");
}
if (Date.now() >= releaseDeadline) throw new Error("detached leader release timed out");
blockMs(20);
}
rmSync(releasePath, { force: true });
rmSync(abortPath, { force: true });
}
const child = spawn(process.platform === "win32" ? "powershell.exe" : "/bin/sh", process.platform === "win32" ? ["-NoProfile", "-Command", payload.codexCmd] : ["-c", payload.codexCmd], {
cwd: payload.cwd,
stdio: "inherit",View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Avoid sending interrupts while the detached launch is in progress; wait for the release confirmation
- If cancellation is intended, use the CLI's abort mechanism (abort report) rather than signaling the leader
- Increase launch timeout / fix slow bootstrap (e.g. tmux server cold start) so release arrives sooner
Defensive patterns
Strategy: try-catch
Try / catch
process.on('SIGINT', () => { /* defer: wait for release or use CLI abort */ });
try { await waitForRelease(); } catch (e) { if (/interrupted before release/.test((e as Error).message)) log('launch cancelled by signal — retry'); } Prevention
- Don't Ctrl-C during the launch window; use the CLI's abort command
- Keep the launching terminal alive until release completes
- Tune timeouts if bootstrap is slow on your machine
When it happens
Trigger: The leader process receives Ctrl-C (SIGINT), kill (SIGTERM), or terminal hangup (SIGHUP) during the window between spawn and the release report file appearing.
Common situations: User presses Ctrl-C while the detached session is still bootstrapping, or a supervisor/tmux rule sends SIGHUP when the launching pane closes too early.
Related errors
- detached launch aborted before release
- detached Hermes leader has no tmux pane identity
- bound setup finalization denied: ${finalization.cleanup.comp
- detached leader release timed out
- detached child process group did not disappear after forced
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/986bdcd956c0ed49.
Report an issue: GitHub.