JuliusBrussee/caveman · error · Error

Aider Caveman config block changed after enable; refusing de

Error message

Aider Caveman config block changed after enable; refusing destructive disable

What it means

Thrown by `caveman disable aider` when ~/.aider.conf.yml drifted after enable (hash differs from after_sha256) and the exact journaled route_block or read_block strings are no longer present verbatim in the file. Caveman only removes what it can match exactly; if its owned blocks were edited or reformatted, removal could cut into your content, so it refuses the destructive disable.

Source

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

    }
    if (mcp.caveman !== undefined) {
      if (operation.owned?.previous_mcp === null || operation.owned?.previous_mcp === undefined) delete mcp.caveman;
      else mcp.caveman = operation.owned.previous_mcp;
    }
    if (Object.keys(mcp).length > 0) root.mcp = mcp;
    else delete root.mcp;
    return jsonBytes(root);
  }
  if (operation.kind === "aider-config") {
    let text = current.toString("utf8");
    const routeBlock = operation.owned?.route_block;
    const readBlock = operation.owned?.read_block;
    const previousRouteLine = operation.owned?.previous_route_line;
    if (typeof routeBlock !== "string" || typeof readBlock !== "string") {
      throw new Error("Aider integration journal lacks owned blocks");
    }
    if (!text.includes(routeBlock) || !text.includes(readBlock)) {
      throw new Error("Aider Caveman config block changed after enable; refusing destructive disable");
    }
    text = text.replace(routeBlock, typeof previousRouteLine === "string" ? previousRouteLine : "");
    text = text.replace(readBlock, "");
    return Buffer.from(text.replace(/\n{3,}/g, "\n\n"));
  }
  if (operation.kind === "aider-core") {
    throw new Error(`${operation.file} changed after enable; refusing destructive disable`);
  }
  if (operation.kind === "hermes-plugin-manifest" || operation.kind === "hermes-plugin-init") {
    throw new Error(`${operation.file} changed after enable; refusing destructive disable`);
  }
  if (operation.kind === "hermes-config") {
    let text = current.toString("utf8");
    const routeBlock = operation.owned?.route_block;
    const previousRouteLines = operation.owned?.previous_route_lines;
    if (typeof routeBlock !== "string" || !Array.isArray(previousRouteLines)) {
      throw new Error("Hermes integration journal lacks owned routing block");
    }

View on GitHub (pinned to 2f49f0e1a3)

Solutions

  1. Restore the owned blocks to the exact strings in owned.route_block / owned.read_block of ~/.caveman/integrations/aider.json, then rerun `caveman disable aider`
  2. Run `caveman doctor aider` first to see per-file drift, and reconcile only the reported lines
  3. If the edits must stay: manually strip the Caveman blocks from ~/.aider.conf.yml and delete ~/.caveman/integrations/aider.json
  4. Re-run `caveman enable aider` to re-journal the current content, then disable immediately

Example fix

# before: the caveman-owned block in ~/.aider.conf.yml was edited
# >>> caveman:native-routing
openai-api-base: http://localhost:9999/v1   # changed from installed route

# after: block matches owned.route_block byte-for-byte, then `caveman disable aider` succeeds
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm the exact owned blocks still exist in ~/.aider.conf.yml before disable
import { readFileSync } from 'node:fs';
const home = process.env.CAVEMAN_HOME ?? `${process.env.HOME}/.caveman`;
const j = JSON.parse(readFileSync(`${home}/integrations/aider.json`, 'utf8'));
const text = readFileSync(`${process.env.HOME}/.aider.conf.yml`, 'utf8');
for (const op of j.operations) {
  if (op.kind === 'aider-config' && (!text.includes(op.owned.route_block) || !text.includes(op.owned.read_block))) {
    console.error('refusing: caveman blocks in .aider.conf.yml were edited');
  }
}

Try / catch

catch (err) { if (err.message.includes('config block changed after enable')) { /* diff .aider.conf.yml against owned blocks in the journal; restore them verbatim; retry once */ } else throw err; }

Prevention

When it happens

Trigger: Editing the Caveman routing or read-tool lines in ~/.aider.conf.yml after `caveman enable aider` — e.g. changing the annotated model/settings lines, reordering them, or a formatter normalizing YAML indentation — then running `caveman disable aider`.

Common situations: Tweaking the OpenAI base URL line Caveman added to point elsewhere; aider or an editor rewriting/reformatting the YAML; merging dotfile changes via git that touch the same lines.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@2f49f0e1a3 (2026-08-18). Data as JSON: /api/errors/10910b95a8faaa5d. Report an issue: GitHub.