JuliusBrussee/caveman · error

existing Aider Caveman block is unjournaled; run `caveman do

Error message

existing Aider Caveman block is unjournaled; run `caveman doctor aider`

What it means

aiderNativeConfig() edits ~/.aider.conf.yml and stamps managed blocks delimited by AIDER_NATIVE_ROUTE/READ BEGIN/END markers. If any marker is present in the file but the install is not journaled (no matching mutation record), the block predates or bypassed Caveman's journal, so safe idempotent merging is impossible and it throws.

Source

Thrown at packages/cli/src/index.ts:6381

      file: pluginPath,
      before: pluginBefore,
      after: Buffer.from(opencodeNativePluginSource()),
      kind: "opencode-plugin",
    },
  ];
}

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 27d5a3981a)

Solutions

  1. Run `caveman doctor aider` to reconcile or remove the unjournaled block
  2. Manually delete the marker-delimited lines (BEGIN..END inclusive) from ~/.aider.conf.yml, then retry the install
  3. Avoid restoring config fragments containing Caveman markers without also restoring ~/.caveman state

Example fix

# before — ~/.aider.conf.yml contains stray markers
# <<< CAVEMAN NATIVE ROUTE BEGIN <<<
openai-api-base: "http://127.0.0.1:8080/w/aider/openai/v1"
# <<< CAVEMAN NATIVE ROUTE END <<<

# after — those lines removed (or `caveman doctor aider`), then reinstall stamps a journaled block
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync } from "node:fs";
const AIDER_MARKERS = [AIDER_NATIVE_ROUTE_BEGIN, AIDER_NATIVE_ROUTE_END, AIDER_NATIVE_READ_BEGIN, AIDER_NATIVE_READ_END];
function aiderConfigClean(path: string): boolean {
  try { const src = readFileSync(path, "utf8"); return !AIDER_MARKERS.some((m) => src.includes(m)); }
  catch { return true; }
}

Try / catch

try { nativeInstallAider(); } catch (e) {
  if (e instanceof Error && /unjournaled/.test(e.message)) {
    spawnSync("caveman", ["doctor", "aider"], { stdio: "inherit" });
    nativeInstallAider();
  } else throw e;
}

Prevention

When it happens

Trigger: Enabling native Aider routing when ~/.aider.conf.yml already contains any AIDER_NATIVE_ROUTE_BEGIN/END or AIDER_NATIVE_READ_BEGIN/END marker without a corresponding journal entry (e.g. after the journal was cleared, or markers were pasted by hand).

Common situations: Restoring .aider.conf.yml from a backup that included Caveman markers while ~/.caveman state/journal was reset; reinstalling caveman after wiping its home dir; sharing dotfiles between machines.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/98e4f11cf2327878. Report an issue: GitHub.