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
- Check whether another shutdown already completed and removed the team config; if so, treat shutdown as done
- Restore or recreate the team config, then re-run shutdown
- 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
- Make shutdown idempotent; tolerate already-deleted configs
- Serialize shutdown per team
- Prevent external deletions of team state during shutdown
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
- shutdown_config_missing_after_commit:${current.name}
- shutdown_${scope}_${kind.replaceAll(' ', '_')}_identity_chan
- invalid auth slot path
- ${label} is not a file: ${path}
- Refusing to overwrite existing ${repoRelative(cwd, missionPa
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/096ad61e84b32cee.
Report an issue: GitHub.