santifer/career-ops · error · Error

-- must be a percentage (e.g. 70 or 70%), got

Error message

--${name} must be a percentage (e.g. 70 or 70%), got "${v}"

What it means

optPct() in buildRow() validates the --threshold and --score fields, which must be percentages (70 or 70%). It delegates to parsePct(); when parsePct returns null (unparseable value), the error is thrown quoting the offending input. This keeps the TSV columns machine-parseable so assessment-log.mjs --summary can compute percentage statistics.

Solutions

  1. Re-run with a valid percentage form: a bare number (70) or number with % (70%).
  2. Convert non-percent scales first: fraction 0.7 → 70; 'A' grade → find the numeric percentage on the platform.
  3. Use a decimal point, not a comma, if the value is fractional (check parsePct's accepted form).
  4. Omit the flag entirely if no percentage exists — optPct() returns '-' when empty instead of throwing.

Example fix

// before
node assessment-log.mjs add --company Acme --platform leetcode --subject dp --score 8/10
// Error: --score must be a percentage (e.g. 70 or 70%), got "8/10"
// after
node assessment-log.mjs add --company Acme --platform leetcode --subject dp --score 80%
Defensive patterns

Strategy: validation

Validate before calling

const isPct = (v) => { const s = String(v ?? '').trim(); return /^\d+(\.\d+)?%?$/.test(s); };
if (fields.threshold != null && fields.threshold !== '' && !isPct(fields.threshold)) throw new Error(`--threshold must be a percentage, got "${fields.threshold}"`);
if (fields.score != null && fields.score !== '' && !isPct(fields.score)) throw new Error(`--score must be a percentage, got "${fields.score}"`);

Type guard

const isPercentage = (v) => /^\d+(\.\d+)?%?$/.test(String(v).trim());

Try / catch

try {
  const row = buildRow(fields, today);
} catch (err) {
  const m = err.message.match(/^--(\w+) must be a percentage .* got "(.*)"$/);
  if (m) {
    const [, flag, bad] = m;
    console.error(`Convert ${flag} value "${bad}" to a number out of 100 (e.g. 70 or 70%).`);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling buildRow() with --threshold or --score set to a non-percentage string, e.g. `--threshold seventy`, `--score 70/100`, `--score "70 %"`, `--threshold 1.5x`, or any value parsePct() cannot interpret as a bare number or number-with-percent-sign.

Common situations: Entering a fraction (0.7) where the tool expects 70; writing '70 percent' in words; a score out of the platform's 0-100 convention like 'A' or 'pass'; locale-decimal input ('70,5'); typos ('7O' with letter O); passing other numeric scales (Codewars kyu, HackerRank stars) that are not percentages.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16). Data as JSON: /api/errors/bf1734712550e56b. Report an issue: GitHub.

Appendix: source

Thrown at assessment-log.mjs:138

}

// --- Append (`add` subcommand) ---
export function buildRow(fields, today) {
  const req = (name) => {
    const v = String(fields[name] ?? '').trim();
    if (!v) throw new Error(`--${name} is required`);
    if (v.includes('\t') || v.includes('\n')) throw new Error(`--${name} must not contain tabs or newlines`);
    return v;
  };
  const opt = (name) => {
    const v = String(fields[name] ?? '').trim();
    if (v.includes('\t') || v.includes('\n')) throw new Error(`--${name} must not contain tabs or newlines`);
    return v || '-';
  };
  const optPct = (name) => {
    const v = String(fields[name] ?? '').trim();
    if (!v) return '-';
    if (parsePct(v) === null) throw new Error(`--${name} must be a percentage (e.g. 70 or 70%), got "${v}"`);
    return v;
  };
  return [
    today, req('company'), opt('report'), req('platform'), req('subject'),
    optPct('threshold'), optPct('score'), opt('stale') === '-' ? '' : opt('stale'),
  ].join('\t');
}

function addEntry(args) {
  const fields = {};
  for (let i = 0; i < args.length; i++) {
    const m = args[i].match(/^--(company|report|platform|subject|threshold|score|stale)$/);
    if (m) { fields[m[1]] = args[i + 1] ?? ''; i++; }
  }
  // LOCAL day: this is the date written into the appended assessments.tsv row,
  // and the UTC day stamped a user record with a day that had not happened yet
  // for anyone west of Greenwich (#3070).
  const today = localToday();

View on GitHub (pinned to aac998c7ed)