{"record":{"id":"e4742aaea618b300","repo":"JuliusBrussee/caveman","slug":"agent-servername-mcp-config-target-changed-w","errorCode":null,"errorMessage":"${agent} ${serverName} MCP config target changed while acquiring lock; refusing mutation","messagePattern":"(.+?) (.+?) MCP config target changed while acquiring lock; refusing mutation","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":12509,"sourceCode":"  }\n  removePendingCopies();\n  process.stderr.write(`${mark(\"warn\")} rolled back interrupted ${agent} ${serverName} MCP transaction\\n`);\n  return \"rolled-back\";\n}\n\nfunction transactOwnedMcpConfig(\n  agent: \"kilo\" | \"qwen\",\n  serverName: string,\n  action: \"install\" | \"uninstall\",\n  mcp?: { command: string; args: string[] },\n  lockedConfigPath?: string,\n): boolean {\n  const plan = action === \"install\"\n    ? agent === \"kilo\" ? planMcpKiloJson(mcp!, serverName) : planMcpQwenJson(mcp!, serverName)\n    : agent === \"kilo\" ? planRemoveMcpKiloJson(serverName) : planRemoveMcpQwenJson(serverName);\n  if (!plan) return false;\n  if (lockedConfigPath && plan.path !== canonicalMcpConfigPath(lockedConfigPath)) {\n    throw new Error(`${agent} ${serverName} MCP config target changed while acquiring lock; refusing mutation`);\n  }\n\n  const markerPath = canonicalOwnedMcpMarkerPath(agent, serverName);\n  const markerBefore = fileBytes(markerPath);\n  if (markerBefore !== null && !validMcpMarkerBytes(markerBefore, agent, serverName)) {\n    throw new Error(`${markerPath} is not a valid Caveman ownership journal; refusing overwrite`);\n  }\n  const markerBeforeMode = markerBefore === null ? 0o600 : statSync(markerPath).mode & 0o777;\n  if (!optionalBytesEqual(fileBytes(markerPath), markerBefore)) {\n    throw new Error(`${markerPath} changed while planning MCP update; refusing overwrite`);\n  }\n  const markerAfter = action === \"install\" ? mcpMarkerBytes(mcp!, mcpServerToolName(serverName)!, plan.path) : null;\n  if (!plan.changed && optionalBytesEqual(markerBefore, markerAfter)) return true;\n\n  const journal: OwnedMcpPendingJournal = {\n    schema_version: 1,\n    transaction_id: randomUUID(),\n    agent,","sourceCodeStart":12491,"sourceCodeEnd":12527,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/5184b3d11ac6a1acb7d44b9bfaa31698157cff97/packages/cli/src/index.ts#L12491-L12527","documentation":"Lock-consistency guard in transactOwnedMcpConfig: the caller acquired a lock on one config path, but by the time the plan was built the canonical MCP config path resolves elsewhere (config location changed, e.g. via env vars or symlink changes while the lock was held). Mutating the new path under a lock for the old path would be unsafe.","triggerScenarios":"Thrown at packages/cli/src/index.ts:12509 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Re-run the operation so the lock is acquired on the current canonical config path","Avoid changing KILO_CONFIG_DIR / KILO_CONFIG or relevant symlinks while an MCP transaction is running","Close competing Caveman instances that may have shifted the config location between lock and plan"],"exampleFix":null,"handlingStrategy":"validation","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-14T05:17:10.506Z"}