{"record":{"id":"12c816dec0ff47d4","repo":"jackwener/OpenCLI","slug":"lichess-label-must-be-a-positive-integer","errorCode":null,"errorMessage":"lichess ${label} must be a positive integer","messagePattern":"lichess (.+?) must be a positive integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/lichess/utils.js","lineNumber":50,"sourceCode":"}\n\nexport function requirePerf(value) {\n    const raw = String(value ?? '').trim();\n    if (!raw) throw new ArgumentError('lichess perf is required (e.g. \"blitz\", \"bullet\", \"rapid\")');\n    if (!LICHESS_PERFS.has(raw)) {\n        throw new ArgumentError(\n            `lichess perf \"${value}\" is not recognised`,\n            `Allowed values: ${[...LICHESS_PERFS].join(', ')}.`,\n        );\n    }\n    return raw;\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(`lichess ${label} must be a positive integer`);\n    }\n    if (n > maxValue) {\n        throw new ArgumentError(`lichess ${label} must be <= ${maxValue}`);\n    }\n    return n;\n}\n\nexport async function lichessFetch(url, label) {\n    let resp;\n    try {\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 lichess.org is reachable from this network.',\n        );\n    }","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/lichess/utils.js#L32-L68","documentation":"This ArgumentError is thrown by `requireBoundedInt` when the numeric argument (labeled via `label`, e.g. 'limit') is not a positive integer — it is non-numeric, fractional, zero, or negative. The library enforces this before using the value as a count.","triggerScenarios":"Calling `limit()` (via `requireBoundedInt`) with e.g. `0`, `-5`, `'abc'`, `2.5`, or `NaN`. Note `Number('')` is 0, so an empty string also fails.","commonSituations":"CLI flags like `--limit 0` or `--limit -1`; passing a string with units ('10 games'); decimals from config files; unset variables coerced to NaN.","solutions":["Pass a positive whole number (>= 1) for the limit","Coerce and validate first: `Number.isInteger(Number(v)) && Number(v) > 0`","Strip units/non-numeric characters from the input","Rely on the defaultValue by passing `undefined` instead of an invalid value"],"exampleFix":"// before\nawait limit('drnik', '0'); // throws: must be a positive integer\n// after\nconst n = Number(raw);\nif (!Number.isInteger(n) || n < 1) throw new Error('limit must be >= 1');\nawait limit('drnik', n);","handlingStrategy":"validation","validationCode":"function toPositiveInt(v, fallback) {\n  if (v == null) return fallback;\n  const n = typeof v === 'number' ? v : Number(String(v).trim());\n  if (!Number.isInteger(n) || n < 1) throw new TypeError(`limit must be a positive integer, got: ${v}`);\n  return n;\n}\nawait limit(userArg, toPositiveInt(rawLimit, 10));","typeGuard":"function isPositiveInt(v) {\n  return typeof v === 'number' && Number.isInteger(v) && v > 0;\n}","tryCatchPattern":"try {\n  await limit(userArg, rawLimit);\n} catch (e) {\n  if (e instanceof ArgumentError && /positive integer/.test(e.message)) {\n    console.error('The limit must be a whole number >= 1, e.g. --limit 10');\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Parse CLI numeric flags with Number() and reject NaN before calling","Strip units/suffixes ('10k', '5 games') from inputs","Pass undefined (not '' or 0) to use the built-in default","Add an argument-parsing layer (e.g. yargs with .number()) to catch this early"],"tags":["lichess","argument-validation","type-error","integer"],"backgroundTag":"invalid-number-input","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}