jackwener/OpenCLI · error · ArgumentError

crates ${label} must be a positive integer

Error message

crates ${label} must be a positive integer

What it means

requireBoundedInt coerces its argument to a number and requires a positive integer before applying the upper bound. Non-integer, zero, negative, or NaN values throw this ArgumentError ('crates limit must be a positive integer'). The adapter fails fast rather than clamping, so callers know their value was not silently rewritten.

Source

Thrown at clis/crates/utils.js:32

}

export function requireCrateName(value) {
    const s = String(value ?? '').trim();
    if (!s) throw new ArgumentError('crates crate name is required (e.g. "serde", "tokio")');
    if (!CRATE_NAME.test(s)) {
        throw new ArgumentError(
            `crates crate name "${value}" is not a valid crates.io name`,
            'Names start with an ASCII letter, then 0-63 chars of letters / digits / "_-".',
        );
    }
    return s;
}

export function requireBoundedInt(value, defaultValue, maxValue, label = 'limit') {
    const raw = value ?? defaultValue;
    const n = typeof raw === 'number' ? raw : Number(raw);
    if (!Number.isInteger(n) || n <= 0) {
        throw new ArgumentError(`crates ${label} must be a positive integer`);
    }
    if (n > maxValue) {
        throw new ArgumentError(`crates ${label} must be <= ${maxValue}`);
    }
    return n;
}

export async function cratesFetch(url, label) {
    let resp;
    try {
        // crates.io requires a descriptive User-Agent per https://crates.io/data-access
        resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });
    }
    catch (err) {
        throw new CommandExecutionError(
            `${label} request failed: ${err?.message ?? err}`,
            'Check that crates.io is reachable from this network.',
        );

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass a positive integer, e.g. --limit 20.
  2. Omit the flag entirely to use the default (20).
  3. Parse/validate user input before passing: Number.isInteger(n) && n > 0.
  4. If you want 'no limit', use the maximum allowed value (see the <= bound error) rather than 0.

Example fix

// before
await cli.crates.search({ query: 'web', limit: 'all' });
// after
await cli.crates.search({ query: 'web', limit: 50 }); // or omit limit for default 20
Defensive patterns

Strategy: validation

Validate before calling

function parseLimit(raw, fallback = 20) {
  if (raw === undefined || raw === null || raw === '') return fallback;
  const n = typeof raw === 'number' ? raw : Number(raw);
  if (!Number.isInteger(n) || n <= 0) throw new Error(`limit must be a positive integer, got ${raw}`);
  return n;
}

Type guard

function isPositiveInt(v) {
  return typeof v === 'number' && Number.isInteger(v) && v > 0;
}

Try / catch

try {
  await cli.crates.search({ query, limit });
} catch (e) {
  if (e instanceof ArgumentError && e.message.includes('must be a positive integer')) {
    console.error('limit must be an integer >= 1; using default 20.');
    return cli.crates.search({ query });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `crates search` with --limit 0, -5, 'abc', 2.5, or '' (empty string coerces to NaN); passing a numeric string with units like '20 items'; passing true/false (coerce to 1/0).

Common situations: Hand-editing scripts with an invalid limit, shell flags receiving an empty value, config files holding '0' to mean 'no limit' (not supported), or locale-formatted numbers with commas.

Related errors


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