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

detached ready report does not bind the inert session

Error message

detached ready report does not bind the inert session

What it means

During detached establishment, the 'ready' report read from the release marker must match the launch nonce, sessionId, sessionName, and leaderPid exactly. If the report is missing, of the wrong kind, or any identity field mismatches, establishment aborts — this binding check prevents attaching OMX to a tmux session created by a different (possibly stale) launch.

Source

Thrown at src/cli/index.ts:6665

                shouldAttach: detachedPreflight.shouldAttach,
                leaderPaneId: detachedLeaderPaneId,
                leaderPanePid: detachedLeaderAuthority?.panePid ?? null,
              })) {
                detachedLeaderPid = report!.leaderPid!;
                return { kind: "success" };
              }
              if (report?.nonce === detachedLaunchNonce && report.sessionId === sessionId && report.sessionName === sessionName && report.leaderPid && report.kind === "failed") {
                detachedLeaderPid = report.leaderPid;
                return { kind: "failure", operation: "session-instructions", error: new Error(report.error || "detached leader setup failed") };
              }
              if (Date.now() >= readyDeadline) return { kind: "failure", operation: "session-instructions", error: new Error("detached leader readiness timed out") };
              blockMs(20);
            }
          },
          createInertSession: async () => {
            const report = readDetachedLeaderReport(releaseMarkerPath);
            if (report?.kind !== "ready" || report.nonce !== detachedLaunchNonce || report.sessionId !== sessionId || report.sessionName !== sessionName || report.leaderPid !== detachedLeaderPid) {
              throw new Error("detached ready report does not bind the inert session");
            }
            return sessionName;
          },
          capturePane: async () => {
            const report = readDetachedLeaderReport(releaseMarkerPath);
            if (!detachedLeaderPaneId || report?.kind !== "ready" || report.paneId !== detachedLeaderPaneId || report.leaderPid !== detachedLeaderPid) {
              throw new Error("detached ready report does not bind the leader pane");
            }
            return detachedLeaderPaneId;
          },
          updateNameMetadata: async () => {
            const state = await readSessionState(cwd, detachedSelectedStateEnv);
            if (state?.session_id !== sessionId || state.tmux_session_name !== sessionName) {
              throw new Error("detached session-name metadata was not committed by the leader");
            }
            return "committed-released";
          },
          updatePaneMetadata: async (_binding, pane) => {

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Remove stale detached launch marker/state files under the OMX state directory before relaunching
  2. Ensure only one detached launch per session/marker path runs at a time
  3. Retry the launch after killing orphaned tmux sessions and leader processes from the prior attempt
  4. If persistent, capture the marker file contents and the expected values to diagnose which field mismatches

Example fix

# before
$ omx launch --detached # after a crashed prior launch

# after
$ omx cleanup --detached   # or: rm -f ~/.omx/state/detached-*.release*
$ omx launch --detached
Defensive patterns

Strategy: fallback

Validate before calling

const report = readDetachedLeaderReport(markerPath);
const ok = report?.kind === "ready" && report.nonce === nonce && report.sessionId === sid && report.sessionName === name && report.leaderPid === pid;
if (!ok) await cleanStaleDetachedState();

Type guard

function bindsLaunch(r: any, l: { nonce: string; sessionId: string; sessionName: string; leaderPid: number }): boolean {
  return r?.kind === "ready" && r.nonce === l.nonce && r.sessionId === l.sessionId && r.sessionName === l.sessionName && r.leaderPid === l.leaderPid;
}

Try / catch

try { establish(); } catch (e) { if (/does not bind the inert session/.test(e.message)) { await cleanStaleMarkers(); return establish(); } throw e; }

Prevention

When it happens

Trigger: readDetachedLeaderReport on the release marker path returns a report whose kind is not 'ready', or whose nonce/sessionId/sessionName/leaderPid differ from the current launch — e.g. a stale marker from a previous launch, a leader that died and a new one wrote a marker, or marker file corruption.

Common situations: Relaunching after an unclean exit where the old release marker file was left behind; concurrent launches sharing a marker path; crashes between marker write and cleanup leaving mismatched state.

Related errors


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