JuliusBrussee/caveman · error

Hermes plugins.enabled uses inline YAML; refusing unsafe…

Error message

Hermes plugins.enabled uses inline YAML; refusing unsafe native merge

What it means

This error is thrown by the Hermes native-integration writer when scanning the top-level `plugins:` section of the Hermes config YAML. It only recognizes a block-style `enabled:` list (a line like `enabled:` followed by list items), because that is the only format it can safely merge entries into. If `plugins.enabled` is written as an inline YAML flow sequence (`enabled: [a, b]`), a naive native merge could corrupt the user's config, so the tool refuses rather than guessing.

Solutions

  1. Convert `plugins.enabled` in the Hermes config from inline YAML (`enabled: ["x", "y"]`) to block style (`enabled:\n - x\n - y`), then rerun the command.
  2. Regenerate the Hermes config with a block-style YAML serializer (no flow style for sequences).
  3. Remove the `enabled` key entirely and let the tool create the block-style list with its own begin/end markers.
  4. Skip native Hermes installation and configure Hermes manually if you must keep the inline format.

Example fix

# before
plugins:
  enabled: [my_plugin, other]
# after
plugins:
  enabled:
    - my_plugin
    - other
Defensive patterns

Strategy: validation

Validate before calling

const lines = cfg.split("\n");
const i = lines.findIndex(l => /^  enabled:\s*\[/.test(l));
if (i !== -1) throw new Error("Rewrite plugins.enabled to block-style YAML before running caveman");

Type guard

const isInlineEnabled = (yaml: string) => /^  enabled:\s*\[/.test(yaml);

Try / catch

try { await cavemanInstallHermes(); } catch (e) { if (String(e.message).includes("inline YAML")) rewritePluginsEnabledToBlockStyle(cfgPath); }

Prevention

When it happens

Trigger: Running a `caveman` command that installs/updates the Hermes native plugin when the Hermes config file contains `plugins:\n enabled: [...]` (inline array) instead of block-style list items.

Common situations: Users or other tools generate Hermes config with `yaml.dump(..., default_flow_style=...)` or JSON-style serialization producing inline arrays; hand-edited configs written in compact YAML style; configs migrated from other agents that use inline lists.

Related errors


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

Appendix: source

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

  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");
  }
  const insertAt = routeIndexes[0] ?? model.start + 1;
  for (const index of [...routeIndexes].sort((a, b) => b - a)) lines.splice(index, 1);
  const routeBlock = [
    `  ${HERMES_NATIVE_ROUTE_BEGIN}`,
    '  provider: "custom"',
    `  base_url: ${yamlQuote(appendUrlPath(gw, "/w/hermes/v1"))}`,
    `  ${HERMES_NATIVE_ROUTE_END}`,
  ];
  lines.splice(insertAt, 0, ...routeBlock);

  let pluginBlock: string | null = null;
  const plugins = topLevelSection(lines, "plugins");
  if (plugins) {
    let enabled = -1;
    for (let i = plugins.start + 1; i < plugins.end; i++) {
      if (/^  enabled:\s*\[/.test(lines[i]!)) throw new Error("Hermes plugins.enabled uses inline YAML; refusing unsafe native merge");
      if (/^  enabled:\s*(?:#.*)?$/.test(lines[i]!)) { enabled = i; break; }
    }
    if (enabled >= 0) {
      if (!hermesNamedPluginEnabled(source, HERMES_NATIVE_PLUGIN_NAME)) {
        const block = [`    ${HERMES_NATIVE_PLUGIN_BEGIN}`, `    - ${HERMES_NATIVE_PLUGIN_NAME}`, `    ${HERMES_NATIVE_PLUGIN_END}`];
        lines.splice(enabled + 1, 0, ...block);
        pluginBlock = block.join("\n");
      }
    } else {
      const block = [`  ${HERMES_NATIVE_PLUGIN_BEGIN}`, "  enabled:", `    - ${HERMES_NATIVE_PLUGIN_NAME}`, `  ${HERMES_NATIVE_PLUGIN_END}`];
      lines.splice(plugins.start + 1, 0, ...block);
      pluginBlock = block.join("\n");
    }
  } else {
    if (lines.length > 0 && lines[lines.length - 1]!.trim()) lines.push("");
    const block = [HERMES_NATIVE_PLUGIN_BEGIN, "plugins:", "  enabled:", `    - ${HERMES_NATIVE_PLUGIN_NAME}`, HERMES_NATIVE_PLUGIN_END];
    lines.push(...block);
    pluginBlock = block.join("\n");

View on GitHub (pinned to 3ee70a1026)