{"record":{"id":"c665e133bcce9da9","repo":"JuliusBrussee/caveman","slug":"aider-config-has-duplicate-openai-api-base-keys-r","errorCode":null,"errorMessage":"Aider config has duplicate openai-api-base keys; refusing unsafe merge","messagePattern":"Aider config has duplicate openai-api-base keys; refusing unsafe merge","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":7415,"sourceCode":"  }];\n}\n\nfunction aiderCorePath(): string {\n  return join(cavemanHome(), \"packs\", \"aider\", \"CAVEMAN.md\");\n}\n\nfunction aiderCoreSource(): string {\n  return `${AIDER_NATIVE_CORE_MARKER}\\n${NATIVE_CORE}\\n\\nHost limits: Aider repository map remains authoritative. Caveman observes provider traffic through local proxy; no pre-tool governance or lifecycle interception is active.\\n`;\n}\n\nfunction aiderNativeConfig(source: string, route: string, corePath: string): { text: string; routeBlock: string; previousRouteLine: string | null; readBlock: string } {\n  if ([AIDER_NATIVE_ROUTE_BEGIN, AIDER_NATIVE_ROUTE_END, AIDER_NATIVE_READ_BEGIN, AIDER_NATIVE_READ_END].some((marker) => source.includes(marker))) {\n    throw new Error(\"existing Aider Caveman block is unjournaled; run `caveman doctor aider`\");\n  }\n  const newline = source.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n  const lines = source.replace(/\\r\\n/g, \"\\n\").split(\"\\n\");\n  const routeIndexes = lines.flatMap((line, index) => /^openai-api-base\\s*:/.test(line) ? [index] : []);\n  if (routeIndexes.length > 1) throw new Error(\"Aider config has duplicate openai-api-base keys; refusing unsafe merge\");\n  const routeBlockLines = [AIDER_NATIVE_ROUTE_BEGIN, `openai-api-base: ${yamlQuote(route)}`, AIDER_NATIVE_ROUTE_END];\n  const routeBlock = routeBlockLines.join(newline);\n  const previousRouteLine = routeIndexes.length === 1 ? lines[routeIndexes[0]!]! : null;\n  if (routeIndexes.length === 1) lines.splice(routeIndexes[0]!, 1, ...routeBlockLines);\n  else {\n    if (lines.some((line) => line.trim() !== \"\") && lines[lines.length - 1]?.trim()) lines.push(\"\");\n    lines.push(...routeBlockLines);\n  }\n\n  const readIndexes = lines.flatMap((line, index) => /^read\\s*:/.test(line) ? [index] : []);\n  if (readIndexes.length > 1) throw new Error(\"Aider config has duplicate read keys; refusing unsafe merge\");\n  let readBlockLines: string[];\n  if (readIndexes.length === 1) {\n    const readIndex = readIndexes[0]!;\n    if (!/^read\\s*:\\s*(?:#.*)?$/.test(lines[readIndex]!)) {\n      throw new Error(\"Aider config uses inline/scalar read; use block-list form before enabling Caveman\");\n    }\n    let end = readIndex + 1;","sourceCodeStart":7397,"sourceCodeEnd":7433,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L7397-L7433","documentation":"aiderNativeConfig() locates the `openai-api-base` key in ~/.aider.conf.yml to replace it with the Caveman route block. If the config declares that key more than once, YAML semantics make the effective value ambiguous, so the installer refuses the merge instead of guessing which key to replace.","triggerScenarios":"Enabling Caveman for Aider when ~/.aider.conf.yml contains two or more top-level `openai-api-base:` lines (e.g. one manually added and one appended by a previous edit).","commonSituations":"Users appending config lines at the end of the file without noticing an existing key earlier in the file; merge conflicts resolved by keeping both lines; copied config snippets pasted over an existing key.","solutions":["Open ~/.aider.conf.yml and delete the duplicate `openai-api-base:` lines, keeping exactly one with your desired value.","Re-run the Caveman enable command after the config has a single `openai-api-base` key.","If a previous Caveman route block caused the duplication, run `caveman doctor aider` to strip stale blocks first."],"exampleFix":"// before\nopenai-api-base: https://api.openai.com/v1\nopenai-api-base: http://localhost:4000/v1\n// after\nopenai-api-base: https://api.openai.com/v1","handlingStrategy":"validation","validationCode":"const lines = readFileSync(aiderCfg, 'utf8').split('\\n');\nconst n = lines.filter((l) => /^openai-api-base\\s*:/.test(l)).length;\nif (n > 1) throw new Error('fix duplicate openai-api-base keys before enabling');","typeGuard":null,"tryCatchPattern":"try {\n  await cavemanEnableAider();\n} catch (e) {\n  if (String(e.message).includes('duplicate openai-api-base')) {\n    dedupeKey(aiderCfg, 'openai-api-base');\n    await cavemanEnableAider();\n  }\n}","preventionTips":["Keep one `openai-api-base` key in ~/.aider.conf.yml.","When pasting config snippets, search the file for the key first.","Resolve merge conflicts by deduplicating keys, not keeping both lines.","Lint YAML configs for duplicate top-level keys before enabling."],"tags":["aider","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"}