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

  1. Avoid sending interrupts while the detached launch is in progress; wait for the release confirmation
  2. If cancellation is intended, use the CLI's abort mechanism (abort report) rather than signaling the leader
  3. 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

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


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/986bdcd956c0ed49. Report an issue: GitHub.