JuliusBrussee/caveman · error
existing Aider Caveman block is unjournaled; run `caveman…
Error message
existing Aider Caveman block is unjournaled; run `caveman doctor aider`
What it means
aiderNativeConfig() refuses to edit ~/.aider.conf.yml if it already contains any Aider Caveman route/read block markers (AIDER_NATIVE_ROUTE_BEGIN/END, AIDER_NATIVE_READ_BEGIN/END). Such markers indicate a prior install whose change was not recorded in the journal, so the installer cannot safely reason about the current state and directs the user to `caveman doctor aider`.
Solutions
- Run `caveman doctor aider` to reconcile/strip the stale blocks, then re-run the enable command.
- Manually remove the Caveman block lines (between the BEGIN/END markers) from ~/.aider.conf.yml, then re-run install.
- Restore ~/.aider.conf.yml to a pre-Caveman version (e.g. from backup) and re-run install.
Example fix
// before (~/.aider.conf.yml) # caveman:native-route-begin openai-api-base: http://... # caveman:native-route-end // after running `caveman doctor aider` (or manual strip) openai-api-base: https://api.openai.com/v1
Defensive patterns
Strategy: validation
Validate before calling
import { readFileSync, existsSync } from 'fs';
const cfg = join(homedir(), '.aider.conf.yml');
if (existsSync(cfg)) {
const s = readFileSync(cfg, 'utf8');
if (/caveman:native-(route|read)-(begin|end)/.test(s)) {
// run `caveman doctor aider` before enabling
}
} Try / catch
try {
await cavemanEnableAider();
} catch (e) {
if (String(e.message).includes('unjournaled')) {
await cavemanDoctorAider();
await cavemanEnableAider();
}
} Prevention
- Always enable/disable Caveman via the CLI so journal state stays in sync.
- Do not restore ~/.aider.conf.yml from backups containing Caveman blocks without running doctor.
- Avoid manually copying configured configs between machines.
- Run `caveman doctor aider` after any manual edit to the Aider config.
When it happens
Trigger: Running `caveman ... aider` enable/install when the Aider config already contains begin/end marker lines from a previous (unjournaled or partially rolled back) Caveman install.
Common situations: A previous install was interrupted before journaling completed; the config was restored from a backup/backup snapshot that still contains blocks; the config file was manually copied from another machine; journal state was deleted while config edits persisted.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- exists and is not exact Caveman-owned content; refusing to…
- existing Hermes Caveman native block is unjournaled; run…
- : MCP ownership journal failed; native config may already…
- Aider Caveman config block changed after enable; refusing…
- Aider config has duplicate openai-api-base keys; refusing…
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/98e4f11cf2327878.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:7410
file: extensionPath,
before,
after,
kind: "pi-extension",
owned: { sha256: bytesHash(after), created_extension_dir: !existsSync(extensionDir) },
}];
}
function aiderCorePath(): string {
return join(cavemanHome(), "packs", "aider", "CAVEMAN.md");
}
function aiderCoreSource(): string {
return `${AIDER_NATIVE_CORE_MARKER}\n${NATIVE_CORE}\n\nHost limits: Aider repository map remains authoritative. Caveman observes provider traffic through local proxy; no pre-tool governance or lifecycle interception is active.\n`;
}
function aiderNativeConfig(source: string, route: string, corePath: string): { text: string; routeBlock: string; previousRouteLine: string | null; readBlock: string } {
if ([AIDER_NATIVE_ROUTE_BEGIN, AIDER_NATIVE_ROUTE_END, AIDER_NATIVE_READ_BEGIN, AIDER_NATIVE_READ_END].some((marker) => source.includes(marker))) {
throw new Error("existing Aider Caveman block is unjournaled; run `caveman doctor aider`");
}
const newline = source.includes("\r\n") ? "\r\n" : "\n";
const lines = source.replace(/\r\n/g, "\n").split("\n");
const routeIndexes = lines.flatMap((line, index) => /^openai-api-base\s*:/.test(line) ? [index] : []);
if (routeIndexes.length > 1) throw new Error("Aider config has duplicate openai-api-base keys; refusing unsafe merge");
const routeBlockLines = [AIDER_NATIVE_ROUTE_BEGIN, `openai-api-base: ${yamlQuote(route)}`, AIDER_NATIVE_ROUTE_END];
const routeBlock = routeBlockLines.join(newline);
const previousRouteLine = routeIndexes.length === 1 ? lines[routeIndexes[0]!]! : null;
if (routeIndexes.length === 1) lines.splice(routeIndexes[0]!, 1, ...routeBlockLines);
else {
if (lines.some((line) => line.trim() !== "") && lines[lines.length - 1]?.trim()) lines.push("");
lines.push(...routeBlockLines);
}
const readIndexes = lines.flatMap((line, index) => /^read\s*:/.test(line) ? [index] : []);
if (readIndexes.length > 1) throw new Error("Aider config has duplicate read keys; refusing unsafe merge");
let readBlockLines: string[];
if (readIndexes.length === 1) {View on GitHub (pinned to 3ee70a1026)