JuliusBrussee/caveman · error

existing Hermes Caveman native block is unjournaled; run…

Error message

existing Hermes Caveman native block is unjournaled; run `caveman doctor hermes`

What it means

hermesNativeConfig() refuses to edit the Hermes config if it already contains any Caveman native block markers (route, plugin, or MCP begin/end). Presence of these markers means a prior install was not journaled, so the installer cannot safely transform the config and tells the user to run `caveman doctor hermes`.

Solutions

  1. Run `caveman doctor hermes` to strip/reconcile the stale blocks, then re-run enable.
  2. Manually delete the Caveman marker-delimited blocks (route, plugin, MCP) from the Hermes config, then re-run install.
  3. Restore the Hermes config to its pre-Caveman state from backup and re-run the enable flow.

Example fix

// before (hermes config.yaml)
model:
  # caveman:native-route-begin
  provider: "custom"
  # caveman:native-route-end
// after `caveman doctor hermes`
model:
  provider: "anthropic"
Defensive patterns

Strategy: validation

Validate before calling

const cfg = readFileSync(hermesCfg, 'utf8');
const markers = [ROUTE_BEGIN, ROUTE_END, PLUGIN_BEGIN, PLUGIN_END, MCP_BEGIN, MCP_END];
if (markers.some((m) => cfg.includes(m))) {
  // run `caveman doctor hermes` before enabling
}

Try / catch

try {
  await cavemanEnableHermes();
} catch (e) {
  if (String(e.message).includes('unjournaled')) {
    await cavemanDoctorHermes();
    await cavemanEnableHermes();
  }
}

Prevention

When it happens

Trigger: Running the Hermes enable/install flow when the Hermes YAML config already includes HERMES_NATIVE_ROUTE/PLUGIN/MCP BEGIN or END marker lines from an earlier, unjournaled install.

Common situations: An install that crashed between writing the config and updating the journal; restoring the Hermes config from a backup that contains blocks; copying a configured config.yaml from another machine; journal files deleted manually.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/4ba193ca3c54f70d. Report an issue: GitHub.

Appendix: source

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

  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 3ee70a1026)