JuliusBrussee/caveman · error
Aider config uses inline/scalar read; use block-list form…
Error message
Aider config uses inline/scalar read; use block-list form before enabling Caveman
What it means
aiderNativeConfig() can only append the Caveman core path to a `read:` key that uses YAML block-list form (`read:` with nothing or a comment after the colon). If the config uses an inline/scalar form such as `read: foo.md`, the installer cannot safely splice entries and asks the user to convert it to block-list form first.
Solutions
- Convert the inline/scalar `read:` to block-list form in ~/.aider.conf.yml (one `- path` item per line, indented).
- Re-run the Caveman enable command after the conversion.
- If a list of files exists inline, expand each element into its own `- ` line under `read:`.
Example fix
// before read: instructions.md // after read: - instructions.md
Defensive patterns
Strategy: validation
Validate before calling
const lines = readFileSync(aiderCfg, 'utf8').split('\n');
const idx = lines.findIndex((l) => /^read\s*:/.test(l));
if (idx !== -1 && !/^read\s*:\s*(?:#.*)?$/.test(lines[idx])) {
// convert `read: value` to block-list form before enabling
} Try / catch
try {
await cavemanEnableAider();
} catch (e) {
if (String(e.message).includes('inline/scalar read')) {
convertReadToBlockList(aiderCfg);
await cavemanEnableAider();
}
} Prevention
- Always use block-list form for `read:` in ~/.aider.conf.yml.
- Avoid `read: file.md` scalar shorthand; write `- file.md` under `read:`.
- Expand inline arrays (`read: [a, b]`) into block lists.
- Check the Caveman Aider docs for the expected config shape before enabling.
When it happens
Trigger: Enabling Caveman for Aider when ~/.aider.conf.yml contains exactly one `read:` line but it has an inline value, e.g. `read: instructions.md` or `read: [a.md, b.md]`.
Common situations: Users who wrote a compact one-line read config; older Aider examples/docs showing scalar `read:`; configs converted from other tools' formats that use inline lists.
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
- Aider config has duplicate openai-api-base keys; refusing…
- Aider config has duplicate read keys; refusing unsafe merge
- Aider Caveman config block changed after enable; refusing…
- auth_token: in is ignored — the inbound token is read only…
- caveman agent: pinned model must use provider/model format
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/c5720ccb7abe5ec7.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:7431
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;
while (end < lines.length && !/^[A-Za-z0-9][A-Za-z0-9_-]*\s*:/.test(lines[end]!)) end++;
readBlockLines = [` ${AIDER_NATIVE_READ_BEGIN}`, ` - ${yamlQuote(corePath)}`, ` ${AIDER_NATIVE_READ_END}`];
lines.splice(end, 0, ...readBlockLines);
} else {
if (lines.some((line) => line.trim() !== "") && lines[lines.length - 1]?.trim()) lines.push("");
readBlockLines = [AIDER_NATIVE_READ_BEGIN, "read:", ` - ${yamlQuote(corePath)}`, AIDER_NATIVE_READ_END];
lines.push(...readBlockLines);
}
const readBlock = readBlockLines.join(newline);
const text = lines.join(newline).replace(/(?:\r?\n)+$/, "") + newline;
return { text, routeBlock, previousRouteLine, readBlock };
}
function aiderNativeMutations(gw: string): NativeMutation[] {
const configPath = join(homedir(), ".aider.conf.yml");
const configBefore = fileBytes(configPath);View on GitHub (pinned to 3ee70a1026)