{"record":{"id":"5616db16b22827df","repo":"Yeachan-Heo/oh-my-codex","slug":"shutdown-config-missing-after-commit-current-nam","errorCode":null,"errorMessage":"shutdown_config_missing_after_commit:${current.name}","messagePattern":"shutdown_config_missing_after_commit:(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/team/runtime.ts","lineNumber":371,"sourceCode":"    const currentManifest = currentManifestBytes === null ? null : JSON.parse(currentManifestBytes) as Record<string, unknown>;\n    await commitTeamMembershipTaskTransaction(current.name, cwd, {\n      baseGeneration,\n      tasks: [],\n      config: { oldBytes: currentConfigBytes, newBytes: JSON.stringify(current, null, 2) },\n      manifest: {\n        oldBytes: currentManifestBytes,\n        newBytes: currentManifest === null ? null : JSON.stringify({\n          ...currentManifest,\n          hud_pane_id: current.hud_pane_id,\n          hud_pane_pid: current.hud_pane_pid,\n          resize_hook_name: current.resize_hook_name,\n          resize_hook_target: current.resize_hook_target,\n          startup_cleanup_panes: current.startup_cleanup_panes,\n        }, null, 2),\n      },\n    });\n    const committed = await readTeamConfig(current.name, cwd);\n    if (!committed) throw new Error(`shutdown_config_missing_after_commit:${current.name}`);\n    return committed;\n  });\n}\n\nexport async function reconcileStartupCleanupPanes(\n  config: TeamConfig,\n  cwd: string,\n): Promise<TeamConfig> {\n  const cleanupPanes = config.startup_cleanup_panes ?? [];\n  if (cleanupPanes.length === 0) return config;\n\n  const teamPaneOwnerId = config.tmux_pane_owner_id?.trim() ?? '';\n  if (!teamPaneOwnerId) throw new Error('startup_cleanup_pane_owner_unavailable:missing_team_owner_id');\n\n  const resolvedPaneIds = new Set<string>();\n  const expectedPanePids: Record<string, number> = {};\n  for (const cleanupPane of cleanupPanes) {\n    if (cleanupPane.pane_id === config.leader_pane_id || cleanupPane.pane_id === config.hud_pane_id) {","sourceCodeStart":353,"sourceCodeEnd":389,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/team/runtime.ts#L353-L389","documentation":"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.","triggerScenarios":"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.","commonSituations":"Two concurrent shutdown commands for the same team, container filesystems with delayed visibility, or state-root symlinks changing mid-operation.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"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; }","preventionTips":["Serialize shutdown operations per team","Verify disk space and state-root permissions","Treat config-vanished-after-commit as a race signal, not corruption"],"tags":["team-runtime","shutdown","race-condition","state-consistency"],"backgroundTag":"write-then-read-inconsistency","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}