JuliusBrussee/caveman · error

${label}:${lineNo}: empty value

Error message

${label}:${lineNo}: empty value

What it means

Thrown by scalar() in scripts/generate-agent-catalog.mjs when a `key:` line has a trailing space, so the regex captures an empty value string instead of no value. The parser distinguishes `key:` (value undefined, opens a nested block) from `key: ` (empty value after the space), and an empty value is meaningless for pricing data, so it is rejected rather than silently treated as null or empty string.

Source

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

      if (Object.prototype.hasOwnProperty.call(row[blockKey], entry.key)) {
        throw new Error(`${label}:${lineNo}: duplicate key "${blockKey}.${entry.key}"`);
      }
      row[blockKey][entry.key] = entry.value;
      continue;
    }
    throw new Error(`${label}:${lineNo}: unexpected indent of ${indent} spaces`);
  }
  return rows;
}

function splitKeyValue(text, label, lineNo) {
  const match = /^([A-Za-z_][A-Za-z0-9_]*):(?: (.*))?$/.exec(text);
  if (match === null) throw new Error(`${label}:${lineNo}: cannot read "${text}" as a "key: value" pair`);
  return { key: match[1], value: match[2] === undefined ? undefined : scalar(match[2], label, lineNo) };
}

function scalar(text, label, lineNo) {
  if (text === "") throw new Error(`${label}:${lineNo}: empty value`);
  if (text === "null") return null;
  if (text === "true") return true;
  if (text === "false") return false;
  if (/^-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?$/.test(text)) {
    const value = Number(text);
    if (!Number.isFinite(value)) throw new Error(`${label}:${lineNo}: "${text}" is not a finite number`);
    return value;
  }
  return text;
}

/** Selects the priced, region-agnostic, USD rows the agent catalog can honestly carry. */
export function selectRows(rows, label = CATALOG_LABEL) {
  const selected = [];
  const skippedByKey = new Map();
  const seen = new Set();
  const record = (key) => {
    let entry = skippedByKey.get(key);

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Go to the line named in the message and either supply a real value (`model: gpt-4o`) or remove the trailing space so the line is exactly `model:` when you intend a nested block.
  2. Check nearby lines for the same trailing-space pattern (e.g. `grep -n ': *$' current.yaml`).
  3. Re-run the generator to verify the catalog parses.

Example fix

# before
  output_per_million: 
# after
  output_per_million: 15
Defensive patterns

Strategy: validation

Validate before calling

// Reject `key: ` lines with an empty captured value before generating.
const bad = text.split("\n").flatMap((line, i) => {
  const m = /^([A-Za-z_][A-Za-z0-9_]*): (.*)$/.exec(line.replace(/\s+$/, ""));
  return m && m[2] === "" ? [i + 1] : [];
});

Try / catch

catch (error) {
  if (/empty value$/.test(error.message)) { const [, lineNo] = error.message.match(/:(\d+):/); fixEmptyValue(lineNo); }
  else throw error;
}

Prevention

When it happens

Trigger: A row line written as `model: ` or `input_per_million: ` — colon, one space, end of line (trailing whitespace is stripped only at end-of-line, so the captured group is the empty string). splitKeyValue then calls scalar("") which raises this error with the file label and line number.

Common situations: Editors or linters that keep a trailing space after the colon; deleting a value while leaving its `key: ` skeleton during catalog editing; copy-pasting from a source that pads values.

Related errors


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