JuliusBrussee/caveman · error
Aider integration journal lacks owned blocks
Error message
Aider integration journal lacks owned blocks
What it means
Aider disable requires the enable journal (operation.owned) to contain the exact route_block and read_block strings that were injected into the Aider config. If either is missing (not a string), the rollback cannot be performed safely, so the tool throws. This is a journal-corruption / missing-state error, not a config error.
Solutions
- Delete/rename the stale journal state and manually remove the Caveman blocks from .aider.conf.yml.
- Re-run enable to regenerate a complete journal, then disable.
- Upgrade the CLI so journal reader and writer use the same schema.
Example fix
// journal state missing blocks (corrupt)
{ "kind": "aider-config", "owned": { "route_block": null } }
// after: re-enable to regenerate
{ "kind": "aider-config", "owned": { "route_block": "# caveman-start ...", "read_block": "# caveman-read ..." } } Defensive patterns
Strategy: validation
Validate before calling
const owned = journal.owned ?? {};
if (typeof owned.route_block !== 'string' || typeof owned.read_block !== 'string') {
throw new Error('Aider journal incomplete; re-enable before disabling');
} Type guard
const hasAiderBlocks = (owned) => typeof owned?.route_block === 'string' && owned.route_block.length > 0 && typeof owned?.read_block === 'string' && owned.read_block.length > 0;
Try / catch
try {
await caveman.disable(['aider']);
} catch (err) {
if (err.message.includes('journal lacks owned blocks')) {
console.error('Journal corrupt/incomplete; remove blocks from .aider.conf.yml manually.');
} else throw err;
} Prevention
- Never hand-edit or prune the Caveman state/journal files.
- Use the same CLI version for enable and disable.
- Re-enable before disabling if you suspect journal corruption.
- Keep a backup of .aider.conf.yml from before enable.
When it happens
Trigger: Running the disable operation with operation.kind === "aider-config" while operation.owned.route_block or operation.owned.read_block is undefined or not a string — e.g. journal written by an older version, partially written, or hand-deleted.
Common situations: Version upgrade changed the journal schema; state file truncated or edited; disabling on a machine where the state was synced incompletely.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Aider Caveman config block changed after enable; refusing…
- Codex integration journal lacks owned blocks
- Hermes integration journal lacks owned routing block
- : MCP ownership journal failed; native config may already…
- MCP transaction journal already exists; refusing overwrite
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/8a8194c96daf58ee.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:8388
const mcp = root.mcp && typeof root.mcp === "object" && !Array.isArray(root.mcp) ? root.mcp as Record<string, unknown> : {};
if (mcp.caveman !== undefined && JSON.stringify(mcp.caveman) !== JSON.stringify(operation.owned?.installed_mcp)) {
throw new Error("OpenCode caveman MCP entry changed after enable; refusing destructive disable");
}
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;View on GitHub (pinned to 3ee70a1026)