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
- 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.
- Regenerate the Hermes config with a block-style YAML serializer (no flow style for sequences).
- Remove the `enabled` key entirely and let the tool create the block-style list with its own begin/end markers.
- 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
- Always serialize Hermes config with block-style sequences (default_flow_style=false, flow_style=False).
- Keep plugins.enabled as a block list; never hand-edit it into an inline array.
- Run a YAML lint that flags flow sequences under plugins.enabled.
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
- Hermes model provider/base_url keys are duplicated…
- aes cipher
- Aider config has duplicate openai-api-base keys; refusing…
- Aider config has duplicate read keys; refusing unsafe merge
- Aider config uses inline/scalar read; use block-list form…
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)