JuliusBrussee/caveman · error

${label}: ${field} must be a finite non-negative number

Error message

${label}: ${field} must be a finite non-negative number

What it means

Thrown by rate() in scripts/generate-agent-catalog.mjs when a pricing field inside a selected (global, USD) row is present but is not a finite non-negative number: negative values, NaN, Infinity, or non-number scalars (booleans, strings) all fail. Null and undefined are legal (they mean 'not offered' and cause the row to be skipped or default to 0 for cache rates), which is why only bad non-null values throw.

Source

Thrown at scripts/generate-agent-catalog.mjs:208

    });
  }
  selected.sort((left, right) => (left.key < right.key ? -1 : left.key > right.key ? 1 : 0));
  const skipped = [...skippedByKey.entries()]
    .map(([key, entry]) => {
      const reasons = [...entry.reasons].sort();
      if (entry.regions.length > 0) {
        reasons.unshift(`priced per region only (${[...entry.regions].sort().join(", ")})`);
      }
      return { key, reason: reasons.join("; ") };
    })
    .sort((left, right) => (left.key < right.key ? -1 : left.key > right.key ? 1 : 0));
  return { selected, skipped };
}

function rate(value, field, label) {
  if (value === undefined || value === null) return null;
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
    throw new Error(`${label}: ${field} must be a finite non-negative number`);
  }
  return value;
}

function number(value) {
  const text = String(value);
  if (!/^(0|[1-9][0-9]*)(\.[0-9]+)?(e[+-]?[0-9]+)?$/.test(text)) {
    throw new Error(`cannot render ${text} as a stable numeric literal`);
  }
  return text;
}

/** Renders the full public/agent/src/catalog.ts module text. */
export function renderCatalogModule(catalogBytes, label = CATALOG_LABEL) {
  const digest = createHash("sha256").update(catalogBytes).digest("hex");
  const { selected, skipped } = selectRows(parseCatalogYaml(catalogBytes.toString("utf8"), label), label);
  if (selected.length === 0) throw new Error(`${label}: no priced region-agnostic rows found`);
  const entries = selected.map(({ key, price }) => [

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Fix the named field to a plain non-negative number (e.g. 0.25); use null (not 0) when the rate genuinely does not exist — the script deliberately maps null cache rates to 0 only for cache fields.
  2. Remove quotes around numeric values in the YAML so they parse as numbers, not strings.
  3. Re-run the generator to confirm the row validates.

Example fix

# before
  pricing:
    input_per_million: "1.5"
    output_per_million: -6
# after
  pricing:
    input_per_million: 1.5
    output_per_million: 6
Defensive patterns

Strategy: type-guard

Type guard

function isValidRate(v) {
  return v === undefined || v === null || (typeof v === "number" && Number.isFinite(v) && v >= 0);
}

Prevention

When it happens

Trigger: A pricing field like `input_per_million: -1` (negative), `input_per_million: true`, `input_per_million: "3"` (quoted string), or a value that parsed to NaN. The field name in the message identifies exactly which rate on which provider/model is bad.

Common situations: Recording a discount as a negative number; quoting prices as strings when pasting from a spreadsheet; a `true`/`false` value left from experimentation; null-vs-0 confusion for cache rates.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/58315ec1cfeb97af. Report an issue: GitHub.