{"record":{"id":"1dfd48a0d8972eec","repo":"jackwener/OpenCLI","slug":"crates-label-must-be-a-positive-integer","errorCode":null,"errorMessage":"crates ${label} must be a positive integer","messagePattern":"crates (.+?) must be a positive integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/crates/utils.js","lineNumber":32,"sourceCode":"}\n\nexport function requireCrateName(value) {\n    const s = String(value ?? '').trim();\n    if (!s) throw new ArgumentError('crates crate name is required (e.g. \"serde\", \"tokio\")');\n    if (!CRATE_NAME.test(s)) {\n        throw new ArgumentError(\n            `crates crate name \"${value}\" is not a valid crates.io name`,\n            'Names start with an ASCII letter, then 0-63 chars of letters / digits / \"_-\".',\n        );\n    }\n    return s;\n}\n\nexport function requireBoundedInt(value, defaultValue, maxValue, label = 'limit') {\n    const raw = value ?? defaultValue;\n    const n = typeof raw === 'number' ? raw : Number(raw);\n    if (!Number.isInteger(n) || n <= 0) {\n        throw new ArgumentError(`crates ${label} must be a positive integer`);\n    }\n    if (n > maxValue) {\n        throw new ArgumentError(`crates ${label} must be <= ${maxValue}`);\n    }\n    return n;\n}\n\nexport async function cratesFetch(url, label) {\n    let resp;\n    try {\n        // crates.io requires a descriptive User-Agent per https://crates.io/data-access\n        resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });\n    }\n    catch (err) {\n        throw new CommandExecutionError(\n            `${label} request failed: ${err?.message ?? err}`,\n            'Check that crates.io is reachable from this network.',\n        );","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/crates/utils.js#L14-L50","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Pass a positive integer, e.g. --limit 20.","Omit the flag entirely to use the default (20).","Parse/validate user input before passing: Number.isInteger(n) && n > 0.","If you want 'no limit', use the maximum allowed value (see the <= bound error) rather than 0."],"exampleFix":"// before\nawait cli.crates.search({ query: 'web', limit: 'all' });\n// after\nawait cli.crates.search({ query: 'web', limit: 50 }); // or omit limit for default 20","handlingStrategy":"validation","validationCode":"function parseLimit(raw, fallback = 20) {\n  if (raw === undefined || raw === null || raw === '') return fallback;\n  const n = typeof raw === 'number' ? raw : Number(raw);\n  if (!Number.isInteger(n) || n <= 0) throw new Error(`limit must be a positive integer, got ${raw}`);\n  return n;\n}","typeGuard":"function isPositiveInt(v) {\n  return typeof v === 'number' && Number.isInteger(v) && v > 0;\n}","tryCatchPattern":"try {\n  await cli.crates.search({ query, limit });\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('must be a positive integer')) {\n    console.error('limit must be an integer >= 1; using default 20.');\n    return cli.crates.search({ query });\n  }\n  throw e;\n}","preventionTips":["Coerce with Number() and check Number.isInteger before passing user input.","Treat 0/negative as invalid, not as 'unlimited'.","Omit the flag to use the built-in default instead of inventing sentinel values.","Reject numeric strings with units or separators at your CLI boundary."],"tags":["argument-validation","integer-parsing","crates-io"],"backgroundTag":"invalid-argument-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}