JuliusBrussee/caveman · error
existing Hermes Caveman native block is unjournaled; run `ca
Error message
existing Hermes Caveman native block is unjournaled; run `caveman doctor hermes`
What it means
hermesNativeConfig() stamps managed blocks into the Hermes YAML config delimited by HERMES_NATIVE_ROUTE/PLUGIN/MCP BEGIN/END markers. If any of these markers is already present in the source while no journal covers it (fresh install path), the file contains a Caveman block Caveman cannot account for, so it refuses to merge.
Source
Thrown at packages/cli/src/index.ts:6692
end: string,
blockLines: string[],
): string | null {
const section = topLevelSection(lines, sectionName);
if (section) {
if (sectionHasChildKey(lines, section, childName)) return null;
lines.splice(section.start + 1, 0, ...blockLines);
return blockLines.join("\n");
}
if (lines.length > 0 && lines[lines.length - 1]!.trim()) lines.push("");
const body = blockLines.filter((line) => !line.includes(begin) && !line.includes(end));
const whole = [begin, `${sectionName}:`, ...body, end];
lines.push(...whole);
return whole.join("\n");
}
function hermesNativeConfig(source: string, gw: string, mcpBinary: string): { text: string; owned: Record<string, unknown> } {
for (const marker of [HERMES_NATIVE_ROUTE_BEGIN, HERMES_NATIVE_ROUTE_END, HERMES_NATIVE_PLUGIN_BEGIN, HERMES_NATIVE_PLUGIN_END, HERMES_NATIVE_MCP_BEGIN, HERMES_NATIVE_MCP_END]) {
if (source.includes(marker)) throw new Error("existing Hermes Caveman native block is unjournaled; run `caveman doctor hermes`");
}
const lines = yamlLines(source);
let model = topLevelSection(lines, "model");
if (!model) {
lines.unshift("model:");
model = topLevelSection(lines, "model")!;
}
const routeIndexes: number[] = [];
const previousRouteLines: string[] = [];
for (let i = model.start + 1; i < model.end; i++) {
if (/^ (provider|base_url):/.test(lines[i]!)) {
routeIndexes.push(i);
previousRouteLines.push(lines[i]!);
}
}
if (new Set(routeIndexes.map((index) => lines[index]!.match(/^ ([^:]+):/)?.[1])).size !== routeIndexes.length) {
throw new Error("Hermes model provider/base_url keys are duplicated; refusing ambiguous install");
}View on GitHub (pinned to 27d5a3981a)
Solutions
- Run `caveman doctor hermes` to reconcile the unjournaled block
- Or delete every HERMES_NATIVE marker-delimited block (BEGIN through END inclusive) from the Hermes config, then retry
- Keep ~/.caveman state and agent configs in sync when restoring from backups
Example fix
# before — hermes config carries orphan markers # <<< CAVEMAN NATIVE ROUTE BEGIN <<< provider: "custom" base_url: "http://127.0.0.1:8080/w/hermes" # <<< CAVEMAN NATIVE ROUTE END <<< # after — block removed (or `caveman doctor hermes`), then install re-stamps journaled blocks
Defensive patterns
Strategy: validation
Validate before calling
import { readFileSync } from "node:fs";
const HERMES_MARKERS = [HERMES_NATIVE_ROUTE_BEGIN, HERMES_NATIVE_ROUTE_END, HERMES_NATIVE_PLUGIN_BEGIN, HERMES_NATIVE_PLUGIN_END, HERMES_NATIVE_MCP_BEGIN, HERMES_NATIVE_MCP_END];
function hermesConfigClean(path: string): boolean {
try { const src = readFileSync(path, "utf8"); return !HERMES_MARKERS.some((m) => src.includes(m)); }
catch { return true; }
} Try / catch
try { nativeInstallHermes(); } catch (e) {
if (e instanceof Error && /unjournaled/.test(e.message)) {
spawnSync("caveman", ["doctor", "hermes"], { stdio: "inherit" });
nativeInstallHermes();
} else throw e;
} Prevention
- Sync ~/.caveman state and Hermes config when restoring from backup/dotfiles
- Don't hand-copy Caveman-marked blocks between environments
- Use caveman doctor hermes after manual config surgery
When it happens
Trigger: Native Hermes install when the Hermes config file already contains any HERMES_NATIVE_* BEGIN/END marker string (e.g. restored from backup, or journal under ~/.caveman was wiped).
Common situations: Restoring the Hermes config from backups or dotfiles after resetting ~/.caveman; reusing a config from another machine; remnants of a previous install.
Related errors
- existing Aider Caveman block is unjournaled; run `caveman do
- cannot read ${agent} agent-native bundle journal: ${(error a
- existing Gemini Caveman routing block is corrupted; run `cav
- existing Codex Caveman block is corrupted; run `caveman doct
- Hermes model provider/base_url keys are duplicated; refusing
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/4ba193ca3c54f70d.
Report an issue: GitHub.