jackwener/OpenCLI · error · ArgumentError

limit must be an integer between 1 and ${max}

Error message

limit must be an integer between 1 and ${max}

What it means

requireLimit validates the user-supplied --limit, coercing strings to numbers and defaulting when empty; it throws this ArgumentError when the value is not an integer in the range [1, max] (max is 40 when called with default 20 from browse). Non-numeric strings, decimals, zero, negatives, and values above max all land here.

Source

Thrown at clis/guazi/utils.js:84

    throw new ArgumentError('city', `unknown city '${cityArg}'. pass a Guazi city code or one of: ${names}`);
}

/** Normalize a clue id: a bare number or a /car-detail/c<id>.htm(l) URL. */
export function normalizeClueId(rawInput) {
    const raw = String(rawInput || '').trim();
    if (!raw) throw new ArgumentError('clue_id must be a non-empty value');
    const m = raw.match(/car-detail\/c(\d+)/) || raw.match(/^c?(\d+)$/);
    if (!m) {
        throw new ArgumentError(`'${rawInput}' does not look like a guazi clue id (a number, or a /car-detail/c<id>.html URL)`);
    }
    return m[1];
}

export function requireLimit(value, def, max) {
    const raw = value == null || value === '' ? def : value;
    const n = typeof raw === 'number' ? raw : Number(String(raw).trim());
    if (!Number.isInteger(n) || n < 1 || n > max) {
        throw new ArgumentError(`limit must be an integer between 1 and ${max}`);
    }
    return n;
}

export function clean(s) {
    return String(s == null ? '' : s).replace(/\s+/g, ' ').trim();
}

export function requireText(value, label) {
    const text = clean(value);
    if (!text) throw new CommandExecutionError(`${label} did not include a stable text value.`);
    return text;
}

export function requireStableId(value, label) {
    const id = String(value ?? '').trim();
    if (!/^\d+$/.test(id)) throw new CommandExecutionError(`${label} did not include a stable numeric id.`);
    return id;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass a plain integer between 1 and 40, e.g. --limit 20.
  2. Remove any unit text or thousand separators from the value.
  3. If you need more rows than max, raise the max argument at the requireLimit call site (clis/guazi/browse.js passes 20 default, 40 max).
  4. Omit --limit entirely to use the default of 20.

Example fix

// before
guazi browse --city bj --limit 100
// after
guazi browse --city bj --limit 40
Defensive patterns

Strategy: validation

Validate before calling

function isValidLimit(v, max = 40) {
  if (v == null || v === '') return true; // default applies
  const n = Number(String(v).trim());
  return Number.isInteger(n) && n >= 1 && n <= max;
}

Type guard

function isLimit(v): v is number {
  const n = typeof v === 'number' ? v : Number(v);
  return Number.isInteger(n) && n >= 1 && n <= 40;
}

Try / catch

try {
  const rows = await guaziBrowse({ city, limit });
} catch (e) {
  if (/limit must be an integer/.test(e.message)) {
    console.error(`--limit must be an integer 1-40, got: ${limit}`);
    process.exitCode = 2;
  } else throw e;
}

Prevention

When it happens

Trigger: 'guazi browse --limit abc' (NaN), --limit 10.5 (not an integer), --limit 0 or --limit -3 (out of range), --limit 100 (above max 40), --limit ' 25 ' is fine because it trims, but 'twenty' is not.

Common situations: Copy-pasting '25 rows' into the flag; setting limit in a config file as a string with a unit ('20 items'); intending page size vs total and passing 1000 expecting all rows.

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 jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/df69c4489e0b1de9. Report an issue: GitHub.