{"record":{"id":"5a19e1df6056fe09","repo":"JuliusBrussee/caveman","slug":"cannot-persist-agentid-servername-mcp-owners","errorCode":null,"errorMessage":"cannot persist ${agentId} ${serverName} MCP ownership journal at ${path}: ${(error as Error).message}","messagePattern":"cannot persist (.+?) (.+?) MCP ownership journal at (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":10292,"sourceCode":"  return canonicalMcpConfigPath(path);\n}\n\n// A native MCP registration and its Caveman ownership journal form one logical\n// write. Prove the journal directory is writable before touching agent config;\n// otherwise Kilo/Qwen would refuse both a later upgrade and removal because the\n// surviving registration has no trustworthy owner.\nfunction preflightMcpServerMarker(agentId: string, serverName: string): void {\n  const path = mcpServerMarkerPath(agentId, serverName);\n  const probe = join(dirname(path), `.${basename(path)}.preflight-${process.pid}-${randomUUID()}`);\n  try {\n    mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n    chmodSync(dirname(path), 0o700);\n    durableAtomicWriteFile(probe, Buffer.alloc(0));\n    unlinkSync(probe);\n    fsyncParentDirectory(probe);\n  } catch (error) {\n    try { unlinkSync(probe); } catch { /* no probe survived */ }\n    throw new Error(`cannot persist ${agentId} ${serverName} MCP ownership journal at ${path}: ${(error as Error).message}`);\n  }\n}\nfunction mcpMarkerPath(agentId: string): string {\n  return mcpServerMarkerPath(agentId, \"caveman\");\n}\nfunction mcpServerInstalled(agentId: string, serverName: string): boolean {\n  try {\n    return statSync(mcpServerMarkerPath(agentId, serverName)).isFile();\n  } catch {\n    return false;\n  }\n}\nfunction mcpInstalled(agentId: string, agentArgs: string[] = []): boolean {\n  if (agentId === \"kilo\" || agentId === \"qwen\") return ownedMcpRegistration(agentId, agentArgs) !== null;\n  return mcpServerInstalled(agentId, \"caveman\");\n}\n\n// configFileOverlayHasMcp asks whether the PROFILE would inject this MCP server","sourceCodeStart":10274,"sourceCodeEnd":10310,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/5184b3d11ac6a1acb7d44b9bfaa31698157cff97/packages/cli/src/index.ts#L10274-L10310","documentation":"Failure of the ownership-journal preflight: before touching the agent's native MCP config, the code proves it can create and remove the journal file under cavemanHome()/mcp. If persisting the journal fails (permissions, full disk, unreadable directory), the write is aborted because the registration and its journal must commit together.","triggerScenarios":"Thrown at packages/cli/src/index.ts:10292 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Fix filesystem permissions on the cavemanHome()/mcp directory so the journal can be created","Free disk space or repair the underlying I/O error reported in the message","Set CAVE_HOME (or the equivalent home override) to a writable location and retry the MCP install"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"5184b3d11ac6a1acb7d44b9bfaa31698157cff97","analyzedAt":"2026-09-06T12:00:26.372Z","contentChangedAt":"2026-09-06T12:00:26.372Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}