{"record":{"id":"794d1aea93940f05","repo":"Yeachan-Heo/oh-my-codex","slug":"detached-launch-requires-a-frozen-available-prefli","errorCode":null,"errorMessage":"detached launch requires a frozen available preflight","messagePattern":"detached launch requires a frozen available preflight","errorType":"exception","errorClass":"DetachedLaunchSafetyError","httpStatus":null,"severity":"critical","filePath":"src/cli/index.ts","lineNumber":6539,"sourceCode":"      }\n      const cleanupPaneIds = buildHudPaneCleanupTargets(\n        listHudWatchPaneIdsInCurrentWindow(currentPaneId, { sessionId, leaderPaneId: currentPaneId }),\n        hudPaneId,\n        currentPaneId,\n      );\n      for (const paneId of cleanupPaneIds) {\n        killTmuxPane(paneId);\n      }\n    }\n    return { postLaunchHandledExternally: false };\n  } else if (launchPolicy === \"direct\") {\n    // Detached HUD sessions require tmux. Skip the bootstrap entirely when the\n    // binary is unavailable so direct launches do not emit noisy ENOENT logs.\n    runCodexBlocking(cwd, launchArgs, codexEnvWithNotify);\n    return { postLaunchHandledExternally: false };\n  } else {\n    if (!detachedPreflight) {\n      throw new DetachedLaunchSafetyError(\"establishment\", new Error(\"detached launch requires a frozen available preflight\"), { transitions: [\"D0\"], rollback: { attempted: [], failures: [] } });\n    }\n    const codexCmd = buildTmuxPaneCommand(\"codex\", launchArgs);\n    const detachedWindowsCodexCmd = nativeWindows\n      ? buildWindowsDetachedChildCommand(\"codex\", launchArgs)\n      : null;\n    const sessionName = buildDetachedTmuxSessionName(cwd, sessionId);\n    const contextKey = detachedControlPlane?.values.OMX_MADMAX_DETACHED_CONTEXT.trim() || undefined;\n    const runsRoot = detachedControlPlane?.values.OMX_RUNS_DIR || resolveMadmaxRunsRoot(process.env);\n    const detachedLaunchNonce = randomUUID();\n    const releaseMarkerPath = join(\n      omxRoot(cwd),\n      \"runtime\",\n      \"detached-release\",\n      `${sessionId}.${detachedLaunchNonce}.release`,\n    );\n    let detachedParentEnvFilePath: string | undefined;\n    let detachedLeaderPaneId: string | null = null;\n    let detachedLeaderAuthority: DetachedLeaderAuthority | null = null;","sourceCodeStart":6521,"sourceCodeEnd":6557,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/index.ts#L6521-L6557","documentation":"Thrown when a detached-tmux launch is attempted without a preflight object that has verified tmux availability. The detached launch state machine requires a frozen preflight (an earlier tmux availability probe whose result is cached) before it can safely drive tmux through the D0 establishment transition, so a missing preflight is treated as a safety invariant violation rather than a recoverable launch failure.","triggerScenarios":"Calling the launch path with launchPolicy 'detached-tmux' (or HUD detached mode) where detachedPreflight is undefined — e.g. tmux check was skipped, a refactor passed the wrong arguments, or an earlier preflight step errored without propagating and left the field unset. The DetachedLaunchSafetyError wraps this with transitions ['D0'] and an empty rollback record.","commonSituations":"Custom scripts or tests invoking the internal launch function directly without running the preflight; tmux not installed so preflight short-circuits to undefined; version upgrades that changed the preflight parameter shape so callers pass undefined.","solutions":["Verify tmux is installed and on PATH (tmux -V), since a failed availability probe yields no frozen preflight","Audit the call site to confirm the preflight result is computed and passed into the detached launch path before it is used","If invoking programmatically, run the preflight helper first and only proceed to the detached launch when it returns a frozen result","Update to a matching version — mismatched internal APIs between modules can pass undefined preflight"],"exampleFix":"// before\nlaunchDetached({ cwd, sessionId, launchPolicy: \"detached-tmux\" }); // detachedPreflight undefined\n\n// after\nconst preflight = await runDetachedPreflight(cwd); // freezes tmux availability\nif (preflight.available) {\n  launchDetached({ cwd, sessionId, launchPolicy: \"detached-tmux\", detachedPreflight: preflight });\n} else {\n  console.error(\"tmux is required for detached launch\");\n}","handlingStrategy":"validation","validationCode":"const preflight = await runDetachedPreflight(cwd);\nif (!preflight?.available) {\n  console.error(\"tmux preflight unavailable; skipping detached launch\");\n  process.exit(1);\n}","typeGuard":"function isFrozenPreflight(p: unknown): p is DetachedPreflight {\n  return !!p && typeof p === \"object\" && (p as any).available === true && !!(p as any).frozen;\n}","tryCatchPattern":"try { launchDetached(args); } catch (e) { if (e instanceof DetachedLaunchSafetyError && e.transitions.includes(\"D0\")) { /* surface tmux/preflight misconfiguration */ } throw e; }","preventionTips":["Always run and await the tmux preflight before choosing detached-tmux launch policy","Fall back to direct (non-detached) launch when the preflight reports tmux unavailable","Keep internal API callers version-locked with the core module"],"tags":["detached-launch","tmux","preflight","invariant"],"backgroundTag":"precondition-not-met","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}