Yeachan-Heo/oh-my-codex · error · Error
shutdown_config_missing_after_commit:${current.name}
Error message
shutdown_config_missing_after_commit:${current.name} What it means
After mutateShutdownConfig writes the updated config it re-reads it to return the committed version; if that read comes back null, the config that was just written cannot be found — a self-inconsistency indicating the write and read disagree (race with deletion, fs sync issue, or state root mismatch). Distinct from 867: the config existed at the start but vanished after commit.
Source
Thrown at src/team/runtime.ts:371
const currentManifest = currentManifestBytes === null ? null : JSON.parse(currentManifestBytes) as Record<string, unknown>;
await commitTeamMembershipTaskTransaction(current.name, cwd, {
baseGeneration,
tasks: [],
config: { oldBytes: currentConfigBytes, newBytes: JSON.stringify(current, null, 2) },
manifest: {
oldBytes: currentManifestBytes,
newBytes: currentManifest === null ? null : JSON.stringify({
...currentManifest,
hud_pane_id: current.hud_pane_id,
hud_pane_pid: current.hud_pane_pid,
resize_hook_name: current.resize_hook_name,
resize_hook_target: current.resize_hook_target,
startup_cleanup_panes: current.startup_cleanup_panes,
}, null, 2),
},
});
const committed = await readTeamConfig(current.name, cwd);
if (!committed) throw new Error(`shutdown_config_missing_after_commit:${current.name}`);
return committed;
});
}
export async function reconcileStartupCleanupPanes(
config: TeamConfig,
cwd: string,
): Promise<TeamConfig> {
const cleanupPanes = config.startup_cleanup_panes ?? [];
if (cleanupPanes.length === 0) return config;
const teamPaneOwnerId = config.tmux_pane_owner_id?.trim() ?? '';
if (!teamPaneOwnerId) throw new Error('startup_cleanup_pane_owner_unavailable:missing_team_owner_id');
const resolvedPaneIds = new Set<string>();
const expectedPanePids: Record<string, number> = {};
for (const cleanupPane of cleanupPanes) {
if (cleanupPane.pane_id === config.leader_pane_id || cleanupPane.pane_id === config.hud_pane_id) {View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Retry the shutdown after confirming with `omx team status` that state is consistent
- Serialize shutdowns per team (the barrier should ensure this — check for barrier bypass)
- Check disk space and permissions on the team state root
Defensive patterns
Strategy: retry
Try / catch
try { await mutateShutdownConfig(...); } catch (e) { if (e instanceof Error && e.message.startsWith('shutdown_config_missing_after_commit:')) { await delay(500); return mutateShutdownConfig(...); /* one retry */ } throw e; } Prevention
- Serialize shutdown operations per team
- Verify disk space and state-root permissions
- Treat config-vanished-after-commit as a race signal, not corruption
When it happens
Trigger: Another process deletes or renames the team state directory between the write and the re-read; or the write silently failed (disk full, permissions) while reporting success.
Common situations: Two concurrent shutdown commands for the same team, container filesystems with delayed visibility, or state-root symlinks changing mid-operation.
Related errors
- shutdown_config_missing:${config.name}
- shutdown_config_missing_after_detached_reconciliation:${sani
- shutdown_${scope}_${kind.replaceAll(' ', '_')}_identity_chan
- invalid auth slot path
- ${label} is not a file: ${path}
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/5616db16b22827df.
Report an issue: GitHub.