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

shutdown_config_missing_after_detached_reconciliation:${sani

Error message

shutdown_config_missing_after_detached_reconciliation:${sanitized}

What it means

Fail-closed guard in team shutdown: after reconciling detached-session destroy receipts, the team config can no longer be read. The shutdown deliberately aborts rather than proceed without authoritative config, naming the team in the message.

Source

Thrown at src/team/runtime.ts:4872

  let skipWorkerAcks = false;
  const sanitized = resolveTeamNameForCurrentContext(teamName, cwd);
  let config = await readTeamConfig(sanitized, cwd);
  if (!config) {
    await reconcileDetachedSessionDestroyReceipt(sanitized, cwd, null);
    await reconcileGonePaneDescendantCleanupDebt(sanitized, cwd);
    // A missing config is not authority over a conventionally named tmux
    // session. It may be another team's or a recycled user session.
    await cleanupTeamState(sanitized, cwd);
    await syncTeamModeStateOnShutdown(sanitized, cwd);
    restoreTeamModelInstructionsFile(sanitized);
    return { commitHygieneArtifacts: null };
  }
  // Reconcile accepted detached-session destruction before any other shutdown
  // effect. A receipt is the only durable authority across the kill/query crash
  // window and is deliberately fail-closed on malformed or unavailable input.
  await reconcileDetachedSessionDestroyReceipt(sanitized, cwd, config);
  config = await readTeamConfig(sanitized, cwd);
  if (!config) throw new Error(`shutdown_config_missing_after_detached_reconciliation:${sanitized}`);
  config = await reconcileStartupCleanupPanes(config, cwd);
  const restoredHudDebtRoot = join(config.team_state_root ?? resolveCanonicalTeamStateRoot(cwd), 'team', sanitized);
  const configuredRestoredHudPaneId = typeof config.hud_pane_id === 'string' && /^%[0-9]+$/.test(config.hud_pane_id)
    ? config.hud_pane_id
    : null;
  const configuredRestoredHudPanePid = typeof config.hud_pane_pid === 'number'
    && Number.isSafeInteger(config.hud_pane_pid)
    && config.hud_pane_pid > 0
    ? config.hud_pane_pid
    : null;
  if (configuredRestoredHudPaneId && configuredRestoredHudPanePid) {
    try {
      // A restored-HUD debt is finalized only when this canonical config
      // transaction records its exact frozen pane identity. A stale config may
      // point to a different HUD after a crash, so replay the pinned debt
      // rather than treating that mismatch as successful finalization.
      finalizeRestoredHudCleanupDebtSync(
        cwd,

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Check whether another shutdown already completed and removed the team config; if so, treat shutdown as done
  2. Restore or recreate the team config, then re-run shutdown
  3. Serialize shutdowns per team (lock) and stop external deletions of team state during shutdown

Example fix

// before
await shutdownTeam(team, cwd);

// after
const config = await readTeamConfig(team, cwd);
if (!config) { /* already gone */ return; }
await withTeamShutdownLock(team, () => shutdownTeam(team, cwd));
Defensive patterns

Strategy: fallback

Validate before calling

const config = await readTeamConfig(teamName, cwd);
if (!config) return; // already shut down

Try / catch

try { await shutdownTeam(t, cwd); } catch (e) { if (/^shutdown_config_missing_after_detached_reconciliation:/.test((e as Error).message)) return; /* idempotent */ throw e; }

Prevention

When it happens

Trigger: Shutting down a team whose config disappears or becomes unreadable specifically after reconcileDetachedSessionDestroyReceipt runs — e.g. the reconciliation itself removed/renamed the state, or an external process deleted the config concurrently.

Common situations: Concurrent shutdown invocations racing on the same team; external cleanup scripts deleting team state mid-shutdown; corrupted config file that readTeamConfig cannot parse (returns null).

Related errors


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