{"record":{"id":"27bb155e8c9b56b1","repo":"jackwener/OpenCLI","slug":"label-must-be-maxvalue-27bb15","errorCode":null,"errorMessage":"${label} must be <= ${maxValue}","messagePattern":"(.+?) must be <= (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/stackoverflow/utils.js","lineNumber":26,"sourceCode":"    ArgumentError,\n    CommandExecutionError,\n    EmptyResultError,\n} from '@jackwener/opencli/errors';\n\nexport const SE_API = 'https://api.stackexchange.com/2.3';\nexport const SE_SITE = 'stackoverflow';\n\nconst UA = 'opencli-stackoverflow (+https://github.com/jackwener/opencli)';\n\n/** Validate `limit` per typed-fail-fast convention (no silent clamp). */\nexport function normalizeLimit(value, defaultValue, maxValue, label = 'limit') {\n    const raw = value ?? defaultValue;\n    const limit = Number(raw);\n    if (!Number.isInteger(limit) || limit <= 0) {\n        throw new ArgumentError(`${label} must be a positive integer`);\n    }\n    if (limit > maxValue) {\n        throw new ArgumentError(`${label} must be <= ${maxValue}`);\n    }\n    return limit;\n}\n\nexport function requireString(value, label) {\n    const raw = String(value ?? '').trim();\n    if (!raw) {\n        throw new ArgumentError(`${label} cannot be empty`);\n    }\n    return raw;\n}\n\n/** Fetch a Stack Exchange API endpoint and return parsed JSON envelope. */\nexport async function seFetch(path, { searchParams } = {}) {\n    const url = new URL(path.startsWith('http') ? path : `${SE_API}${path.startsWith('/') ? '' : '/'}${path}`);\n    if (searchParams) {\n        for (const [k, v] of Object.entries(searchParams)) {\n            if (v == null || v === '') continue;","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/stackoverflow/utils.js#L8-L44","documentation":"ArgumentError from normalizeLimit when the limit is a valid positive integer but exceeds the command's maxValue (e.g. 100 for related/tag). The Stack Exchange API caps pagesize, so the CLI enforces the cap up front instead of letting the API reject or silently truncate.","triggerScenarios":"`stackoverflow related <id> --limit 500` or `stackoverflow tag <tag> --limit 101`; a script building pagesize from an unbounded config value.","commonSituations":"Trying to bulk-download many results in one call; a config value tuned for a different tool with a higher cap; misunderstanding that the cap is per-request, not overall.","solutions":["Lower --limit to <= the stated max (100 for these commands).","Paginate by varying the `page` parameter across multiple calls of <=100 each if you need more results.","Clamp in your own script before invoking: const capped = Math.min(limit, 100)."],"exampleFix":"// before\nstackoverflow related 79935770 --limit 500\n// after\nstackoverflow related 79935770 --limit 100","handlingStrategy":"validation","validationCode":"function capLimit(v, max = 100) {\n  const n = Number(v);\n  if (!Number.isInteger(n) || n <= 0 || n > max) throw new TypeError(`limit must be an integer in 1..${max}`);\n  return n;\n}","typeGuard":"function isBoundedLimit(v, max = 100) { return Number.isInteger(v) && v > 0 && v <= max; }","tryCatchPattern":"try {\n  return await run({ limit });\n} catch (e) {\n  if (e.name === 'ArgumentError' && /must be <= \\d+/.test(e.message)) {\n    return run({ limit: 100 }); // clamp to the documented max\n  }\n  throw e;\n}","preventionTips":["Clamp limits to 100 in your own tooling before calling the CLI.","Paginate with the page parameter instead of raising pagesize for bulk needs.","Centralize the max in a constant shared between your scripts and CLI invocations."],"tags":["argument-validation","rate-limit","cli"],"backgroundTag":"parameter-out-of-range","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}