JuliusBrussee/caveman · error
${label}: duplicate region-agnostic row ${key}
Error message
${label}: duplicate region-agnostic row ${key} What it means
Thrown by selectRows() in scripts/generate-agent-catalog.mjs when two rows share the same `provider/model` key and both are region-agnostic (`region: global`). The generated catalog.ts keys a single price entry per provider/model, so a duplicate would silently overwrite the first price; the generator refuses instead. Only priced, USD, global rows reach this check, so duplicates among regional or non-USD rows do not trigger it.
Source
Thrown at scripts/generate-agent-catalog.mjs:175
const key = `${row.provider}/${row.model}`;
if (row.region !== REGION_AGNOSTIC) {
skipRegional(key, row.region);
continue;
}
if (row.currency !== REQUIRED_CURRENCY) {
skip(key, `priced in ${row.currency}, not ${REQUIRED_CURRENCY}`);
continue;
}
if (row.pricing === null || typeof row.pricing !== "object" || Array.isArray(row.pricing)) {
throw new Error(`${label}: ${key} has no pricing block`);
}
const input = rate(row.pricing.input_per_million, `${key}.input_per_million`, label);
const output = rate(row.pricing.output_per_million, `${key}.output_per_million`, label);
if (input === null || output === null) {
skip(key, "no list price for input or output tokens");
continue;
}
if (seen.has(key)) throw new Error(`${label}: duplicate region-agnostic row ${key}`);
seen.add(key);
// reasoning_output_per_million is null on every provider that bills thinking
// tokens at the plain output rate. catalogCost subtracts reasoning tokens
// out of output before pricing them, so a 0 here would make them free.
const reasoning = rate(row.pricing.reasoning_output_per_million, `${key}.reasoning_output_per_million`, label);
selected.push({
key,
price: {
inputPerMillion: input,
outputPerMillion: output,
cacheReadPerMillion: rate(row.pricing.cache_read_input_per_million, `${key}.cache_read_input_per_million`, label) ?? 0,
cacheWritePerMillion: rate(row.pricing.cache_write_input_per_million, `${key}.cache_write_input_per_million`, label) ?? 0,
reasoningPerMillion: reasoning ?? output,
},
});
}
selected.sort((left, right) => (left.key < right.key ? -1 : left.key > right.key ? 1 : 0));
const skipped = [...skippedByKey.entries()]View on GitHub (pinned to 27d5a3981a)
Solutions
- Search current.yaml for the duplicated `provider/model` named in the message and delete or rename the stale row.
- If the duplicate is intentional (e.g. a variant), give it a distinct model identifier so the catalog key is unique.
- Re-run the generator; the duplicate-key check should pass.
Example fix
# before
- provider: acme
model: acme-1
region: global
currency: USD
pricing: {input...}
- provider: acme
model: acme-1
region: global
currency: USD
pricing: {input...}
# after (one row remains)
- provider: acme
model: acme-1
region: global
currency: USD
pricing: {input...} Defensive patterns
Strategy: validation
Validate before calling
// Detect duplicate global USD keys before running the generator.
const keys = rows.filter((r) => r.region === "global" && r.currency === "USD").map((r) => `${r.provider}/${r.model}`);
const dup = keys.filter((k, i) => keys.indexOf(k) !== i); Prevention
- After a copy-paste edit, search the file for the model name to confirm exactly one global row exists.
- Treat merge conflicts in current.yaml as a signal to re-check for duplicated rows.
When it happens
Trigger: Two entries in current.yaml with identical `provider:` and `model:` values where both have `region: global` and valid USD pricing — e.g. a copy-pasted row edited only in prices.
Common situations: Copy-pasting an existing row to update prices and forgetting to change the model name; a merge that keeps both sides of a pricing edit; appending a provider's full row set twice.
Related errors
- ${label}: ${key} has no pricing block
- %s: provider, model, and region are required
- %s %s/%s: unsupported currency %q
- %s %s/%s: invalid pricing
- cave_provider_usage_unpriced
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/c8988df7a4c0298f.
Report an issue: GitHub.