{"record":{"id":"d6050e5ddd7260fa","repo":"JuliusBrussee/caveman","slug":"target-integration-journal-disappeared-during-r","errorCode":null,"errorMessage":"${target} integration journal disappeared during repair","messagePattern":"(.+?) integration journal disappeared during repair","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":8294,"sourceCode":"    return false;\n  }\n  cleanupNativeAgentFiles(target, disabled);\n  const name = findAgent(target)?.display_name ?? target;\n  process.stderr.write(`${mark(\"ok\")} ${name}: ${target === \"aider\" ? \"shallow\" : \"native\"} Caveman disabled; unrelated host edits preserved\\n`);\n  return true;\n}\n\nfunction repairNativeAgent(target: NativeAgent): void {\n  if (!readNativeJournal(target) && !readPendingNativeJournal(target)) {\n    enableNative([target]);\n    return;\n  }\n  const profile = findAgent(target)!;\n  const gw = gatewayURL();\n  withIntegrationLock(target, () => {\n    recoverPendingNativeInstallUnlocked(target);\n    const journal = readNativeJournal(target);\n    if (!journal) throw new Error(`${target} integration journal disappeared during repair`);\n    if (!which(binOf(profile))) throw new Error(`${profile.display_name} not found on PATH`);\n    const mcpBinary = target === \"aider\" ? undefined : nativeMcpBinaryRequired();\n    nativeProxyBinaryRequired(gw);\n    const journalBytes = readFileSync(nativeJournalPath(target));\n    const current = restoreNativeJournalFiles(journal);\n    try {\n      const mutations = nativeMutationsFor(target, gw, mcpBinary);\n      applyNativeMutations(target, profile, mutations);\n    } catch (error) {\n      for (const item of current) {\n        try { writeNativeRestoration(item.file, item.bytes); } catch { /* original error remains authority */ }\n      }\n      atomicWriteFile(nativeJournalPath(target), journalBytes);\n      throw error;\n    }\n  });\n  process.stderr.write(`${mark(\"ok\")} ${profile.display_name}: native Caveman repaired; unrelated host edits preserved\\n`);\n}","sourceCodeStart":8276,"sourceCodeEnd":8312,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/5184b3d11ac6a1acb7d44b9bfaa31698157cff97/packages/cli/src/index.ts#L8276-L8312","documentation":"repairNativeAgent first checks that either the committed journal or a pending journal exists, then inside the integration lock runs crash recovery (recoverPendingNativeInstallUnlocked) and re-reads the committed journal; this error means the re-read found nothing. The usual cause is that a pending (crashed) transaction was rolled back by recovery — leaving no committed journal — or a concurrent `caveman disable <agent>` deleted the journal between the two reads.","triggerScenarios":"`caveman doctor <agent> --fix` when a crashed `caveman enable <agent>` left a .pending-<agent>.json that recovery rolls back (enable never committed), or when another terminal runs `caveman disable <agent>` at the same moment. A journal file deleted by hand mid-command also triggers it.","commonSituations":"Interrupting an enable (Ctrl-C, machine sleep, crash) and then immediately running doctor --fix; running disable and doctor concurrently from two shells; scripts invoking multiple caveman integration commands in parallel.","solutions":["Simply rerun `caveman doctor <agent> --fix` — with both journals now absent, it takes the enableNative path and rebuilds the integration cleanly","Make sure no other caveman disable/enable/doctor command for the same agent is running concurrently; run integration commands serially","If it recurs without concurrency, check for external deletion of ~/.caveman/integrations/<agent>.json (cron, dotfile cleaners)"],"exampleFix":"# before: recovery rolled back a pending enable, journal gone\ncaveman doctor claude --fix\n# >> claude integration journal disappeared during repair\n\n# after: state is now consistent; rerun rebuilds the integration\ncaveman doctor claude --fix","handlingStrategy":"retry","validationCode":"// Ensure no concurrent integration command and journals are stable before repair\nimport { existsSync } from 'node:fs';\nconst home = process.env.CAVEMAN_HOME ?? `${process.env.HOME}/.caveman`;\nconst committed = `${home}/integrations/codex.json`;\nconst pending = `${home}/integrations/.pending-codex.json`;\n// snapshot twice with a beat between; require stability if you plan to repair\nconst snap = () => [committed, pending].map((p) => existsSync(p)).join(',');\nconst a = snap(); await new Promise((r) => setTimeout(r, 250));\nif (snap() !== a) console.error('journal state changing — another caveman process is active');","typeGuard":null,"tryCatchPattern":"catch (err) {\n  if (err.message.includes('journal disappeared during repair')) {\n    // state resolved (pending rolled back or concurrent disable finished):\n    // re-check and run the command again from scratch — it now takes the enable path\n    return execSync('caveman doctor codex --fix');\n  }\n  throw err;\n}","preventionTips":["Never run caveman disable/enable/doctor for the same agent concurrently","In scripts, sequence integration commands with `&&` rather than parallel jobs","Do not delete ~/.caveman/integrations files while a command is running"],"tags":["repair","race-condition","journal","doctor","recovery"],"backgroundTag":"concurrent-modification-race","analyzedSha":"5184b3d11ac6a1acb7d44b9bfaa31698157cff97","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}