JuliusBrussee/caveman · error · Error
Hermes routing block changed after enable; refusing destruct
Error message
Hermes routing block changed after enable; refusing destructive disable
What it means
Thrown while disabling or repairing the Hermes integration when the Hermes config file drifted (hash differs from after_sha256) and the exact journaled route_block string no longer appears in the file. Caveman replaces that block with the original previous_route_lines on disable; if the block was edited or removed after enable, an automatic restore could mangle the config, so it refuses.
Source
Thrown at packages/cli/src/index.ts:7715
}
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");
}
if (!text.includes(routeBlock)) throw new Error("Hermes routing block changed after enable; refusing destructive disable");
text = text.replace(routeBlock, previousRouteLines.filter((line): line is string => typeof line === "string").join("\n"));
for (const key of ["plugin_block", "mcp_block"] as const) {
const block = operation.owned?.[key];
if (block === null || block === undefined) continue;
if (typeof block !== "string" || !text.includes(block)) throw new Error(`Hermes ${key.replace("_block", "")} block changed after enable; refusing destructive disable`);
text = text.replace(block, "");
}
return Buffer.from(text);
}
const rootBlock = operation.owned?.root_block;
const tablesBlock = operation.owned?.tables_block;
if (typeof rootBlock !== "string" || typeof tablesBlock !== "string") throw new Error("Codex integration journal lacks owned blocks");
let text = current.toString("utf8");
for (const [block, begin] of [[rootBlock, CODEX_NATIVE_ROOT_BEGIN], [tablesBlock, CODEX_NATIVE_TABLES_BEGIN]] as const) {
if (text.includes(begin) && !text.includes(block)) throw new Error("Codex Caveman config block changed after enable; refusing destructive disable");
text = text.replace(`${block}\n\n`, "").replace(`\n\n${block}\n`, "\n").replace(block, "");
}
return Buffer.from(text);View on GitHub (pinned to 2f49f0e1a3)
Solutions
- Run `caveman doctor hermes` to confirm drift, then restore the exact owned.route_block string from ~/.caveman/integrations/hermes.json into the config
- If you already manually removed the block: finish cleanup by hand and delete the journal file — disable has nothing left to restore
- Re-run `caveman enable hermes` to re-journal current state, then disable before further edits
Example fix
# before: caveman routing block in hermes config was edited # >>> caveman:native-routing (modified lines...) # after: paste back the exact owned.route_block, then run `caveman disable hermes`
Defensive patterns
Strategy: try-catch
Validate before calling
import { readFileSync } from 'node:fs';
const home = process.env.CAVEMAN_HOME ?? `${process.env.HOME}/.caveman`;
const j = JSON.parse(readFileSync(`${home}/integrations/hermes.json`, 'utf8'));
const op = j.operations.find((o) => o.kind === 'hermes-config');
const text = readFileSync(op.file, 'utf8');
if (!text.includes(op.owned.route_block)) console.error('routing block missing/edited — restore it or clean up manually'); Try / catch
catch (err) { if (err.message.includes('routing block changed after enable')) { /* restore owned.route_block verbatim, or if you already removed it deliberately, delete the journal and finish cleanup manually */ } else throw err; } Prevention
- Do not edit or delete caveman routing lines in the hermes config; disable via the CLI instead
- After any manual fiddling, run `caveman enable hermes` to re-sync the journal
When it happens
Trigger: Editing or deleting the Caveman routing lines inside the Hermes config after `caveman enable hermes`, then running `caveman disable hermes` or `caveman doctor hermes --fix`.
Common situations: Changing the gateway URL line Caveman added; deleting the block manually and forgetting the journal; a config migration tool reformatting the file so the exact string no longer matches.
Related errors
- Hermes ${key.replace("_block", "")} block changed after enab
- Codex Caveman config block changed after enable; refusing de
- ${agent} ${event} Caveman hook changed after enable; refusin
- ${operation.file} was removed after enable; refusing destruc
- Claude ANTHROPIC_BASE_URL changed after enable; refusing des
AI-assisted analysis of JuliusBrussee/caveman@2f49f0e1a3 (2026-08-18).
Data as JSON: /api/errors/4ee7a775110a1fc0.
Report an issue: GitHub.