{"record":{"id":"9e449e168cb14b05","repo":"JuliusBrussee/caveman","slug":"hermes-model-provider-base-url-keys-are-duplicated","errorCode":null,"errorMessage":"Hermes model provider/base_url keys are duplicated; refusing ambiguous install","messagePattern":"Hermes model provider/base_url keys are duplicated; refusing ambiguous install","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":7747,"sourceCode":"  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]) {\n    if (source.includes(marker)) throw new Error(\"existing Hermes Caveman native block is unjournaled; run `caveman doctor hermes`\");\n  }\n  const lines = yamlLines(source);\n  let model = topLevelSection(lines, \"model\");\n  if (!model) {\n    lines.unshift(\"model:\");\n    model = topLevelSection(lines, \"model\")!;\n  }\n  const routeIndexes: number[] = [];\n  const previousRouteLines: string[] = [];\n  for (let i = model.start + 1; i < model.end; i++) {\n    if (/^  (provider|base_url):/.test(lines[i]!)) {\n      routeIndexes.push(i);\n      previousRouteLines.push(lines[i]!);\n    }\n  }\n  if (new Set(routeIndexes.map((index) => lines[index]!.match(/^  ([^:]+):/)?.[1])).size !== routeIndexes.length) {\n    throw new Error(\"Hermes model provider/base_url keys are duplicated; refusing ambiguous install\");\n  }\n  const insertAt = routeIndexes[0] ?? model.start + 1;\n  for (const index of [...routeIndexes].sort((a, b) => b - a)) lines.splice(index, 1);\n  const routeBlock = [\n    `  ${HERMES_NATIVE_ROUTE_BEGIN}`,\n    '  provider: \"custom\"',\n    `  base_url: ${yamlQuote(appendUrlPath(gw, \"/w/hermes/v1\"))}`,\n    `  ${HERMES_NATIVE_ROUTE_END}`,\n  ];\n  lines.splice(insertAt, 0, ...routeBlock);\n\n  let pluginBlock: string | null = null;\n  const plugins = topLevelSection(lines, \"plugins\");\n  if (plugins) {\n    let enabled = -1;\n    for (let i = plugins.start + 1; i < plugins.end; i++) {\n      if (/^  enabled:\\s*\\[/.test(lines[i]!)) throw new Error(\"Hermes plugins.enabled uses inline YAML; refusing unsafe native merge\");\n      if (/^  enabled:\\s*(?:#.*)?$/.test(lines[i]!)) { enabled = i; break; }","sourceCodeStart":7729,"sourceCodeEnd":7765,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L7729-L7765","documentation":"When installing the Hermes native route block, the installer collects existing `provider:` and `base_url:` lines under the `model:` section so it can replace them. If the same key appears more than once in that section, the effective value is ambiguous (duplicates by key name), so the installer refuses the install rather than produce an ambiguous config.","triggerScenarios":"Running the Hermes enable flow when the `model:` section of the Hermes YAML config contains duplicate `provider:` or duplicate `base_url:` keys (e.g. two `provider:` lines at the two-space indent level).","commonSituations":"Hand-edited configs where a provider/base_url pair was appended while the original remained; merge conflicts keeping both lines; pasted snippets from docs duplicating existing keys.","solutions":["Edit the Hermes config's `model:` section so `provider:` and `base_url:` each appear exactly once with your desired values.","Re-run the Caveman enable command after de-duplicating the keys.","Run `caveman doctor hermes` first if a stale Caveman route block contributed the duplicates."],"exampleFix":"// before\nmodel:\n  provider: \"anthropic\"\n  base_url: https://api.anthropic.com\n  provider: \"openai\"\n// after\nmodel:\n  provider: \"anthropic\"\n  base_url: https://api.anthropic.com","handlingStrategy":"validation","validationCode":"const lines = readFileSync(hermesCfg, 'utf8').split('\\n');\nconst keys = lines.flatMap((l, i) => /^  (provider|base_url):/.test(l) ? [l.match(/^  ([^:]+):/)[1]] : []);\nif (new Set(keys).size !== keys.length) {\n  // dedupe provider/base_url keys in the model: section before enabling\n}","typeGuard":null,"tryCatchPattern":"try {\n  await cavemanEnableHermes();\n} catch (e) {\n  if (String(e.message).includes('duplicated')) {\n    dedupeModelKeys(hermesCfg, ['provider', 'base_url']);\n    await cavemanEnableHermes();\n  }\n}","preventionTips":["Keep exactly one `provider:` and one `base_url:` line inside the `model:` section.","Replace existing values in place instead of appending duplicates.","Resolve merge conflicts by deduplicating YAML keys.","Lint the Hermes YAML for duplicate keys before enabling."],"tags":["hermes","config","yaml","duplicate-keys"],"backgroundTag":"conflicting-config-options","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}