{"record":{"id":"38db2d307cf94dee","repo":"JuliusBrussee/caveman","slug":"agent-servername-mcp-transaction-postflight-mismatch","errorCode":null,"errorMessage":"${agent} ${serverName} MCP transaction postflight mismatch","messagePattern":"(.+?) (.+?) MCP transaction postflight mismatch","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":12937,"sourceCode":"  durableCreateFile(locatorPath, pendingBytes);\n  try {\n    durableCreateFile(configPendingPath, pendingBytes);\n  } catch (error) {\n    durableUnlink(locatorPath);\n    throw error;\n  }\n\n  try {\n    if (action === \"install\") {\n      if (plan.changed) durableReplaceFileIfUnchanged(plan.path, plan.before, plan.after, plan.beforeMode);\n      if (!optionalBytesEqual(markerBefore, markerAfter)) durableReplaceFileIfUnchanged(markerPath, markerBefore, markerAfter);\n    } else {\n      if (!optionalBytesEqual(markerBefore, markerAfter)) durableReplaceFileIfUnchanged(markerPath, markerBefore, markerAfter);\n      if (plan.changed) durableReplaceFileIfUnchanged(plan.path, plan.before, plan.after, plan.beforeMode);\n    }\n    if (optionalBytesHash(fileBytes(plan.path)) !== journal.config_after_sha256\n      || optionalBytesHash(fileBytes(markerPath)) !== journal.marker_after_sha256) {\n      throw new Error(`${agent} ${serverName} MCP transaction postflight mismatch`);\n    }\n    durableUnlink(configPendingPath);\n    durableUnlink(locatorPath);\n    return true;\n  } catch (error) {\n    try {\n      const recovery = recoverOwnedMcpTransaction(readOwnedMcpConfigPending(plan.path) ?? readOwnedMcpPendingLocator(agent, serverName));\n      if (recovery === \"finalized\") return true;\n    } catch (recoveryError) {\n      throw new Error(`${agent} ${serverName} MCP transaction failed and safe recovery was blocked: ${(recoveryError as Error).message}; original error: ${(error as Error).message}`);\n    }\n    throw new Error(`${agent} ${serverName} MCP transaction failed and rolled back: ${(error as Error).message}`);\n  }\n}\n\nfunction withOwnedMcpTransactionLock<T>(\n  agent: \"kilo\" | \"qwen\",\n  serverName: string,","sourceCodeStart":12919,"sourceCodeEnd":12955,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L12919-L12955","documentation":"After applying the planned config and marker writes, the CLI re-hashes both files and verifies they match the journal's recorded after-hashes (config_after_sha256 / marker_after_sha256). If they don't, the writes were skipped (durableReplaceFileIfUnchanged detected concurrent modification) or something rewrote the files mid-transaction; the transaction aborts and safe rollback is attempted.","triggerScenarios":"Thrown in transactOwnedMcpConfig's commit phase when optionalBytesHash(fileBytes(plan.path)) !== journal.config_after_sha256 || the marker hash !== marker_after_sha256 — i.e. a conditional replace was skipped or a concurrent writer changed the files between write and verification.","commonSituations":"The agent application (or a config watcher) rewrote its MCP config during the transaction; a second caveman process raced the same transaction; read-only or full disk silently degraded the write; the plan's after-state was computed from stale input JSON.","solutions":["Re-run the command: the built-in rollback runs first, and once the competing writer is gone the retried transaction should commit cleanly.","Close/pause the agent and any config-sync tools while running 'caveman mcp install/uninstall'.","Check write permissions and free disk space on the config directory; fix and retry.","If rollback was also blocked, the CLI reports 'failed and safe recovery was blocked' — resolve recovery per the recovery-error guidance, then retry."],"exampleFix":"// before: agent rewrites config mid-install\ncaveman mcp install kilo   # postflight mismatch, rolled back\n// after: stop the agent, then install\npkill -f claude && caveman mcp install kilo","handlingStrategy":"try-catch","validationCode":"import { accessSync, W_OK } from 'node:fs';\ntry { accessSync(configPath, W_OK); }\ncatch { console.error('config not writable — the transaction postflight will fail'); }\n// also ensure the agent process is stopped before installing","typeGuard":"function agentConfigIsQuiescent(configPath: string, quietMs = 1000): Promise<boolean> {\n  const s1 = statSync(configPath).mtimeMs;\n  return new Promise(r => setTimeout(() => r(statSync(configPath).mtimeMs === s1), quietMs));\n}","tryCatchPattern":"try {\n  runMcpCommand();\n} catch (e) {\n  if (String(e.message).includes('transaction failed and rolled back')) {\n    stopAgentProcesses();\n    runMcpCommand(); // retry after rollback\n  }\n}","preventionTips":["Stop the target agent before running caveman mcp install/uninstall","Disable config auto-save/watchers on agent config files during transactions","Verify write permissions and free disk space in the config directory","Retry the command after any postflight mismatch — rollback restores prior state safely"],"tags":["mcp","transaction","race-condition","integrity-check"],"backgroundTag":"checksum-mismatch","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}