JuliusBrussee/caveman · error

Aider config has duplicate openai-api-base keys; refusing…

Error message

Aider config has duplicate openai-api-base keys; refusing unsafe merge

What it means

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.

Solutions

  1. Open ~/.aider.conf.yml and delete the duplicate `openai-api-base:` lines, keeping exactly one with your desired value.
  2. Re-run the Caveman enable command after the config has a single `openai-api-base` key.
  3. If a previous Caveman route block caused the duplication, run `caveman doctor aider` to strip stale blocks first.

Example fix

// before
openai-api-base: https://api.openai.com/v1
openai-api-base: http://localhost:4000/v1
// after
openai-api-base: https://api.openai.com/v1
Defensive patterns

Strategy: validation

Validate before calling

const lines = readFileSync(aiderCfg, 'utf8').split('\n');
const n = lines.filter((l) => /^openai-api-base\s*:/.test(l)).length;
if (n > 1) throw new Error('fix duplicate openai-api-base keys before enabling');

Try / catch

try {
  await cavemanEnableAider();
} catch (e) {
  if (String(e.message).includes('duplicate openai-api-base')) {
    dedupeKey(aiderCfg, 'openai-api-base');
    await cavemanEnableAider();
  }
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

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/c665e133bcce9da9. Report an issue: GitHub.

Appendix: source

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

  }];
}

function aiderCorePath(): string {
  return join(cavemanHome(), "packs", "aider", "CAVEMAN.md");
}

function aiderCoreSource(): string {
  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`;
}

function aiderNativeConfig(source: string, route: string, corePath: string): { text: string; routeBlock: string; previousRouteLine: string | null; readBlock: string } {
  if ([AIDER_NATIVE_ROUTE_BEGIN, AIDER_NATIVE_ROUTE_END, AIDER_NATIVE_READ_BEGIN, AIDER_NATIVE_READ_END].some((marker) => source.includes(marker))) {
    throw new Error("existing Aider Caveman block is unjournaled; run `caveman doctor aider`");
  }
  const newline = source.includes("\r\n") ? "\r\n" : "\n";
  const lines = source.replace(/\r\n/g, "\n").split("\n");
  const routeIndexes = lines.flatMap((line, index) => /^openai-api-base\s*:/.test(line) ? [index] : []);
  if (routeIndexes.length > 1) throw new Error("Aider config has duplicate openai-api-base keys; refusing unsafe merge");
  const routeBlockLines = [AIDER_NATIVE_ROUTE_BEGIN, `openai-api-base: ${yamlQuote(route)}`, AIDER_NATIVE_ROUTE_END];
  const routeBlock = routeBlockLines.join(newline);
  const previousRouteLine = routeIndexes.length === 1 ? lines[routeIndexes[0]!]! : null;
  if (routeIndexes.length === 1) lines.splice(routeIndexes[0]!, 1, ...routeBlockLines);
  else {
    if (lines.some((line) => line.trim() !== "") && lines[lines.length - 1]?.trim()) lines.push("");
    lines.push(...routeBlockLines);
  }

  const readIndexes = lines.flatMap((line, index) => /^read\s*:/.test(line) ? [index] : []);
  if (readIndexes.length > 1) throw new Error("Aider config has duplicate read keys; refusing unsafe merge");
  let readBlockLines: string[];
  if (readIndexes.length === 1) {
    const readIndex = readIndexes[0]!;
    if (!/^read\s*:\s*(?:#.*)?$/.test(lines[readIndex]!)) {
      throw new Error("Aider config uses inline/scalar read; use block-list form before enabling Caveman");
    }
    let end = readIndex + 1;

View on GitHub (pinned to 3ee70a1026)