Yeachan-Heo/oh-my-codex · error · Error

detached leader release timed out

Error message

detached leader release timed out

What it means

The leader polls release/abort report files on a 20ms loop until a deadline; if neither appears in time, it throws this timeout.

Source

Thrown at src/cli/index.ts:7105

      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",
      ...(process.platform === "win32" ? {} : { detached: true }),
    });
    let escalation: NodeJS.Timeout | undefined;
    const signalChildTree = (signal: NodeJS.Signals, force = false): void => {
      if (!child.pid) return;
      try {
        if (process.platform === "win32") execFileSync("taskkill", ["/PID", String(child.pid), "/T", ...(force ? ["/F"] : [])], { stdio: "ignore" });
        else process.kill(-child.pid, signal);
      } catch {}
    };

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Check that the report directory is writable and not on a slow/stalled filesystem
  2. Look for a crashed or hung parent launcher process (check its logs) and retry
  3. Report a bug if the deadline is consistently too short for your environment (large sessions, cold tmux server)
Defensive patterns

Strategy: retry

Try / catch

try { await launchDetached(); } catch (e) {
  if ((e as Error).message === 'detached leader release timed out') await sleep(2000), launchDetached(); // one retry
  else throw e;
}

Prevention

When it happens

Trigger: Date.now() exceeds releaseDeadline without a valid release or abort report — launcher process hung, killed, or too slow to write the report file.

Common situations: Heavily loaded machine, tmux server startup latency, report file path permissions issues, or the parent CLI crashed before writing the report.

Understand the failure class

Related errors


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