jackwener/OpenCLI · error · ArgumentError

${label} must be a positive integer

Error message

${label} must be a positive integer

What it means

normalizePositiveInteger validates that a numeric CLI option (bookRank, limit, fragmentSize) is a positive integer before use. The library throws ArgumentError when Number(value) is not an integer or is <= 0, i.e. the user passed a fractional, zero, negative, or non-numeric value for that option.

Source

Thrown at clis/weread/book-search.js:28

    return String(value || '')
        .replace(/<[^>]+>/g, '')
        .replace(/&#x([0-9a-fA-F]+);/gi, (_, n) => String.fromCharCode(parseInt(n, 16)))
        .replace(/&#(\d+);/g, (_, n) => String.fromCharCode(Number(n)))
        .replace(/&nbsp;/g, ' ')
        .replace(/&amp;/g, '&')
        .replace(/&quot;/g, '"')
        .trim();
}

function normalizeSearchText(value) {
    return String(value || '').replace(/\s+/g, ' ').trim();
}

function normalizePositiveInteger(value, defaultValue, label, maxValue) {
    const raw = value ?? defaultValue;
    const n = Number(raw);
    if (!Number.isInteger(n) || n <= 0) {
        throw new ArgumentError(`${label} must be a positive integer`);
    }
    if (maxValue != null && n > maxValue) {
        throw new ArgumentError(`${label} must be <= ${maxValue}`);
    }
    return n;
}

function parseOptionalFiniteNumber(value) {
    if (value == null || value === '')
        return null;
    const n = Number(value);
    return Number.isFinite(n) ? n : null;
}

function parseHasMore(value) {
    if (value === true || value === 1 || value === '1')
        return true;
    if (value === false || value === 0 || value === '0')

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass a whole number >= 1 for the offending option
  2. Omit the option entirely so the built-in defaultValue is used (null/undefined falls through via value ?? defaultValue)
  3. Fix the calling script so the variable holds a numeric string, e.g. LIMIT=20 not LIMIT=''
  4. Check the exact label in the message to see which option failed validation

Example fix

// before
weread book-search --query zen --limit 0
// after
weread book-search --query zen --limit 10
Defensive patterns

Strategy: validation

Validate before calling

function ensurePositiveInt(v, name) {
  const n = Number(v);
  if (!Number.isInteger(n) || n <= 0) throw new TypeError(`${name} must be a positive integer, got: ${JSON.stringify(v)}`);
  return n;
}
ensurePositiveInt(opts.limit, 'limit');

Type guard

const isPositiveInt = (v) => Number.isInteger(Number(v)) && Number(v) > 0;

Try / catch

try {
  await runCommand(['book-search', '--query', q, '--limit', String(limit)]);
} catch (e) {
  if (e instanceof ArgumentError && e.message.includes('must be a positive integer')) {
    console.error(`Bad numeric option: ${e.message}`); process.exitCode = 2;
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the book-search command with an option such as --book-rank, --limit, or --fragment-size set to 0, -1, 2.5, 'abc', an empty-but-non-null string, or a value that Number() coerces to NaN or Infinity.

Common situations: Users typo a flag value (--limit=ten), paste values with trailing spaces or units ('20 pages'), script variables are empty strings rather than unset (empty string coerces to 0), or shell interpolation yields a fractional number.

Related errors


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