jackwener/OpenCLI · error · ArgumentError

${label} must be an integer between ${min} and ${max}, got $

Error message

${label} must be an integer between ${min} and ${max}, got ${JSON.stringify(value)}

What it means

requireBoundedInteger coerces its input to a number (falling back to a default when nullish) and requires an integer. If the coerced value is NaN, fractional, or otherwise not an integer, it throws ArgumentError '<label> must be an integer between <min> and <max>, got <JSON of value>'.

Source

Thrown at clis/_shared/search-adapter.js:15

import { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';

export function requireSearchQuery(value, label = 'keyword') {
  const query = String(value ?? '').trim();
  if (!query) {
    throw new ArgumentError(`${label} cannot be empty`);
  }
  return query;
}

export function requireBoundedInteger(value, defaultValue, min, max, label) {
  const raw = value ?? defaultValue;
  const parsed = typeof raw === 'number' ? raw : Number(raw);
  if (!Number.isInteger(parsed)) {
    throw new ArgumentError(`${label} must be an integer between ${min} and ${max}, got ${JSON.stringify(value)}`);
  }
  if (parsed < min || parsed > max) {
    throw new ArgumentError(`${label} must be between ${min} and ${max}, got ${parsed}`);
  }
  return parsed;
}

export function requireNonNegativeInteger(value, defaultValue, label) {
  const raw = value ?? defaultValue;
  const parsed = typeof raw === 'number' ? raw : Number(raw);
  if (!Number.isInteger(parsed) || parsed < 0) {
    throw new ArgumentError(`${label} must be a non-negative integer, got ${JSON.stringify(value)}`);
  }
  return parsed;
}

export function unwrapBrowserResult(value) {
  if (value && typeof value === 'object' && !Array.isArray(value) && 'session' in value && 'data' in value) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass a plain integer (or numeric string) within [min, max], e.g. 50 not '50 results' or '1,000'.
  2. Strip units/thousands separators and call Number(value) yourself, checking Number.isInteger before invoking.
  3. Fix the config/schema so the field is typed as an integer; rely on the default by passing null/undefined rather than ''.

Example fix

// before
requireBoundedInteger('1,000', 25, 1, 100, 'limit')  // NaN -> throws
// after
requireBoundedInteger(1000, 25, 1, 100, 'limit')     // still range-checked, or use 100
// or sanitize:
requireBoundedInteger(parseInt(raw.replace(/[,.]/g, ''), 10), 25, 1, 100, 'limit')
Defensive patterns

Strategy: type-guard

Validate before calling

const n = Number(raw);
if (!Number.isInteger(n)) throw new Error(`${label} must be an integer, got: ${JSON.stringify(raw)}`);

Type guard

const isInt = (v) => typeof v === 'number' && Number.isInteger(v);
const isIntLike = (v) => isInt(v) || (typeof v === 'string' && /^-?\d+$/.test(v.trim()));

Try / catch

try {
  const limit = requireBoundedInteger(raw, 25, 1, 100, 'limit');
} catch (err) {
  if (err.name === 'ArgumentError' && err.message.includes('must be an integer')) {
    console.error(`--limit must be a whole number in range; got ${err.message}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing a non-numeric string ('abc', '10px'), a fractional number (2.5), NaN, a boolean, or an object/array as the limit-related option (e.g. --limit, --max-results).

Common situations: String CLI args with units or whitespace ('50 results') not parsed by Number; JSON config supplying floats; environment variables containing commas ('1,000'); undefined handled fine (default applies) but empty string '' coerces to NaN and fails.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/0176285d22f82b0e. Report an issue: GitHub.