{"record":{"id":"9dbc446c06f31054","repo":"jackwener/OpenCLI","slug":"rubygems-label-must-be-a-positive-integer","errorCode":null,"errorMessage":"rubygems ${label} must be a positive integer","messagePattern":"rubygems (.+?) must be a positive integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/rubygems/utils.js","lineNumber":25,"sourceCode":"import { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';\n\nexport const GEMS_BASE = 'https://rubygems.org/api/v1';\nconst UA = 'opencli-rubygems-adapter (+https://github.com/jackwener/opencli)';\n\n// RubyGems gem name pattern (mirrors the rubygems-server validation).\nconst GEM_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\n\nexport function requireString(value, label) {\n    const s = String(value ?? '').trim();\n    if (!s) throw new ArgumentError(`rubygems ${label} cannot be empty`);\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(`rubygems ${label} must be a positive integer`);\n    }\n    if (n > maxValue) {\n        throw new ArgumentError(`rubygems ${label} must be <= ${maxValue}`);\n    }\n    return n;\n}\n\nexport function requireGemName(value) {\n    const s = String(value ?? '').trim();\n    if (!s) {\n        throw new ArgumentError('rubygems gem name is required (e.g. \"rails\", \"sidekiq\")');\n    }\n    if (s.length > 100 || !GEM_NAME.test(s)) {\n        throw new ArgumentError(\n            `rubygems gem \"${value}\" is not a valid gem name`,\n            'Use letters / digits / \"._-\", starting with a letter or digit (max 100 chars).',\n        );\n    }","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/rubygems/utils.js#L7-L43","documentation":"requireBoundedInt in clis/rubygems/utils.js validates numeric options such as limit: the value (or its Number() coercion) must be an integer > 0. Otherwise it throws ArgumentError(`rubygems ${label} must be a positive integer`). The default (30 for search) is used when the option is omitted, so this only fires on an explicitly provided bad value.","triggerScenarios":"Calling search({ query: 'rails', limit: 0 }), limit: -5, limit: 'ten', limit: 2.5, or limit: NaN — any explicitly passed limit that is not a positive integer.","commonSituations":"Users typing `--limit 0` expecting 'unlimited'; passing a numeric string with trailing spaces or locale formatting ('1,000'); a config file supplying a float or non-numeric limit.","solutions":["Pass a positive integer, e.g. `--limit 10`, or omit the flag to use the default of 30.","Sanitize caller input before the call: coerce and validate `const n = Number.parseInt(v, 10)` and check `n > 0`.","If you want 'all results', pick a large bound like limit: 100 (the maxValue) instead of 0."],"exampleFix":"// before\nawait search({ query: 'rails', limit: 0 }); // throws\n\n// after\nawait search({ query: 'rails', limit: 100 }); // valid upper bound","handlingStrategy":"validation","validationCode":"function coerceLimit(v, def = 30) {\n  if (v == null) return def;\n  const n = Number(v);\n  if (!Number.isInteger(n) || n <= 0) throw new Error(`limit must be a positive integer, got ${v}`);\n  return n;\n}","typeGuard":"function isPositiveInt(v) {\n  return typeof v === 'number' && Number.isInteger(v) && v > 0;\n}","tryCatchPattern":"try {\n  await search({ query, limit: args.limit });\n} catch (e) {\n  if (e instanceof ArgumentError && /positive integer/.test(e.message)) {\n    console.error('Use --limit <n> with n >= 1');\n  } else throw e;\n}","preventionTips":["Coerce CLI strings with Number.parseInt and validate before passing.","Never use 0 to mean 'unlimited' — use the maxValue (100) instead.","Document that limit defaults to 30 when omitted."],"tags":["validation","argument-error","cli-input","numeric"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}