{"record":{"id":"c8988df7a4c0298f","repo":"JuliusBrussee/caveman","slug":"label-duplicate-region-agnostic-row-key","errorCode":null,"errorMessage":"${label}: duplicate region-agnostic row ${key}","messagePattern":"(.+?): duplicate region-agnostic row (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/generate-agent-catalog.mjs","lineNumber":175,"sourceCode":"    const key = `${row.provider}/${row.model}`;\n    if (row.region !== REGION_AGNOSTIC) {\n      skipRegional(key, row.region);\n      continue;\n    }\n    if (row.currency !== REQUIRED_CURRENCY) {\n      skip(key, `priced in ${row.currency}, not ${REQUIRED_CURRENCY}`);\n      continue;\n    }\n    if (row.pricing === null || typeof row.pricing !== \"object\" || Array.isArray(row.pricing)) {\n      throw new Error(`${label}: ${key} has no pricing block`);\n    }\n    const input = rate(row.pricing.input_per_million, `${key}.input_per_million`, label);\n    const output = rate(row.pricing.output_per_million, `${key}.output_per_million`, label);\n    if (input === null || output === null) {\n      skip(key, \"no list price for input or output tokens\");\n      continue;\n    }\n    if (seen.has(key)) throw new Error(`${label}: duplicate region-agnostic row ${key}`);\n    seen.add(key);\n    // reasoning_output_per_million is null on every provider that bills thinking\n    // tokens at the plain output rate. catalogCost subtracts reasoning tokens\n    // out of output before pricing them, so a 0 here would make them free.\n    const reasoning = rate(row.pricing.reasoning_output_per_million, `${key}.reasoning_output_per_million`, label);\n    selected.push({\n      key,\n      price: {\n        inputPerMillion: input,\n        outputPerMillion: output,\n        cacheReadPerMillion: rate(row.pricing.cache_read_input_per_million, `${key}.cache_read_input_per_million`, label) ?? 0,\n        cacheWritePerMillion: rate(row.pricing.cache_write_input_per_million, `${key}.cache_write_input_per_million`, label) ?? 0,\n        reasoningPerMillion: reasoning ?? output,\n      },\n    });\n  }\n  selected.sort((left, right) => (left.key < right.key ? -1 : left.key > right.key ? 1 : 0));\n  const skipped = [...skippedByKey.entries()]","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/scripts/generate-agent-catalog.mjs#L157-L193","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\n- provider: acme\n  model: acme-1\n  region: global\n  currency: USD\n  pricing: {input...}\n- provider: acme\n  model: acme-1\n  region: global\n  currency: USD\n  pricing: {input...}\n# after (one row remains)\n- provider: acme\n  model: acme-1\n  region: global\n  currency: USD\n  pricing: {input...}","handlingStrategy":"validation","validationCode":"// Detect duplicate global USD keys before running the generator.\nconst keys = rows.filter((r) => r.region === \"global\" && r.currency === \"USD\").map((r) => `${r.provider}/${r.model}`);\nconst dup = keys.filter((k, i) => keys.indexOf(k) !== i);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["yaml","duplicate","pricing","catalog"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}