Yeachan-Heo/oh-my-codex · critical · Error
detached active record does not bind the ready leader
Error message
detached active record does not bind the ready leader
What it means
Before publishing, OMX reads the detached active record (per-context or default state/detached-active-record.json) and requires every identity field — launch_nonce, leader_pid, session_id, tmux_session_name, tmux_pane_id — to match the ready leader. Any missing record or mismatched field aborts, since publishing a record that binds the wrong session would misroute later clients.
Source
Thrown at src/cli/index.ts:6693
},
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) => {
const state = await readSessionState(cwd, detachedSelectedStateEnv);
if (state?.session_id !== sessionId || state.tmux_pane_id !== pane) {
throw new Error("detached pane metadata was not committed by the leader");
}
return "committed-released";
},
publishActiveRecord: async () => {
const activeRecordPath = contextKey ? madmaxDetachedActiveRecordPath(runsRoot, contextKey) : join(omxRoot(cwd), "state", "detached-active-record.json");
const record = readMadmaxDetachedActiveRecord(activeRecordPath);
if (!record || record.launch_nonce !== detachedLaunchNonce || record.leader_pid !== detachedLeaderPid || record.session_id !== sessionId || record.tmux_session_name !== sessionName || record.tmux_pane_id !== detachedLeaderPaneId) throw new Error("detached active record does not bind the ready leader");
const bytes = readFileSync(activeRecordPath, "utf-8");
return { bytes, digest: createHash("sha256").update(bytes).digest("hex"), nonce: detachedLaunchNonce };
},
finalizeSetupFailure: async () => {},
releaseBarrier: async () => {
if (!detachedLeaderPid) throw new Error("detached leader PID missing before release");
publishDetachedReleaseMarker(releaseMarkerPath, detachedLaunchNonce, sessionId, sessionName, detachedLeaderPid, detachedHudAuthority ?? undefined);
},
abortAndAwaitFinalization: async () => {
// The leader has the retained binding. Publishing abort is the only
// outer action permitted after a D9 write failure; a mismatched or
// missing report leaves every artifact and the tmux session intact.
if (!detachedLeaderPid) {
rollbackFromPreReportAuthority = detachedLeaderAuthority !== null;
return { acknowledged: false, rollbackAuthorized: rollbackFromPreReportAuthority };
}
const current = readDetachedLeaderReport(releaseMarkerPath);
if (current?.nonce === detachedLaunchNonce && current.sessionId === sessionId &&View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Remove state/detached-active-record.json (and any context-keyed variants) plus release markers, then relaunch
- Ensure contextKey/runsRoot resolution is identical between the leader environment and the outer launch (consistent env vars)
- Serialize detached launches per context
- If persistent, dump the record file and compare each field against the current launch values to find the divergent writer
Defensive patterns
Strategy: fallback
Validate before calling
const record = readMadmaxDetachedActiveRecord(activeRecordPath); const binds = record && record.launch_nonce === nonce && record.leader_pid === pid && record.session_id === sid && record.tmux_session_name === name && record.tmux_pane_id === pane; if (!binds) await cleanStaleDetachedState();
Type guard
function recordBindsLeader(r: any, l: { nonce: string; pid: number; sid: string; name: string; pane: string }): boolean {
return !!r && r.launch_nonce === l.nonce && r.leader_pid === l.pid && r.session_id === l.sid && r.tmux_session_name === l.name && r.tmux_pane_id === l.pane;
} Try / catch
try { establish(); } catch (e) { if (/active record does not bind/.test(e.message)) { await cleanStaleDetachedState(); return establish(); } throw e; } Prevention
- Delete detached-active-record.json and markers after crashed launches
- Keep contextKey/runsRoot env identical on both sides of the launch
- One detached launch per context at a time
When it happens
Trigger: readMadmaxDetachedActiveRecord returns null (leader never wrote the record) or a record with any field diverging from the current launch — stale record from a prior launch, leader crash before publishing, context key selecting a different record path, or split/racing processes overwriting the record.
Common situations: Relaunching after crashes without cleaning state; madmax/multi-context setups where contextKey resolution differs between leader and validator; concurrent detached launches; disk issues dropping the leader's write.
Related errors
- detached ready report does not bind the inert session
- detached ready report does not bind the leader pane
- autoresearch_active_run_exists
- autoresearch_active_mode_exists
- detached launch requires a frozen available preflight
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/6eb4944b8cd7c827.
Report an issue: GitHub.