jackwener/OpenCLI · error · ArgumentError

crates ${label} must be <= ${maxValue}

Error message

crates ${label} must be <= ${maxValue}

What it means

requireBoundedInt enforces an upper bound on integer arguments (label defaults to 'limit'); values above maxValue throw this ArgumentError (e.g. 'crates limit must be <= 100'). This keeps requests within what the crates.io API (per_page) and the adapter are willing to serve.

Source

Thrown at clis/crates/utils.js:35

    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.',
        );
    }
    if (resp.status === 404) {
        throw new EmptyResultError(label, `crates.io returned 404 for ${url}.`);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Cap the value at the documented maximum (100 for search) before calling.
  2. Use Math.min(limit, 100) when deriving the limit programmatically.
  3. Paginate with repeated calls if you need more than the maximum results.
  4. Catch ArgumentError and re-prompt with the valid range.

Example fix

// before
await cli.crates.search({ query: 'serde', limit: 1000 });
// after
await cli.crates.search({ query: 'serde', limit: Math.min(userLimit, 100) });
Defensive patterns

Strategy: validation

Validate before calling

const MAX_SEARCH_LIMIT = 100;
function clampLimit(raw) {
  const n = Number(raw);
  if (!Number.isInteger(n) || n <= 0) throw new Error('limit must be a positive integer');
  if (n > MAX_SEARCH_LIMIT) throw new Error(`limit must be <= ${MAX_SEARCH_LIMIT}`);
  return n;
}

Type guard

function isWithinLimit(v, max) {
  return typeof v === 'number' && Number.isInteger(v) && v > 0 && v <= max;
}

Try / catch

try {
  await cli.crates.search({ query, limit });
} catch (e) {
  if (e instanceof ArgumentError && /must be <= \d+/.test(e.message)) {
    return cli.crates.search({ query, limit: 100 });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `crates search` with --limit greater than 100 (the maxValue used by search), or any other adapter call whose label-specific max is exceeded, e.g. --limit 500.

Common situations: Trying to fetch 'everything' with a huge limit, porting a limit from another API with a different cap, or computing a limit dynamically (e.g. total results count) and passing it straight through.

Related errors


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