{"record":{"id":"69a042acb14830d4","repo":"jackwener/OpenCLI","slug":"label-must-be-max","errorCode":null,"errorMessage":"${label} must be <= ${max}","messagePattern":"(.+?) must be <= (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/booking/search.js","lineNumber":17,"sourceCode":"import {\n  ArgumentError,\n  CommandExecutionError,\n  EmptyResultError,\n} from '@jackwener/opencli/errors';\nimport { cli, Strategy } from '@jackwener/opencli/registry';\n\nconst DATE_RE = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nfunction normalizePositiveInt(value, defaultValue, label, max) {\n  const raw = value ?? defaultValue;\n  const n = Number(raw);\n  if (!Number.isInteger(n) || n <= 0) {\n    throw new ArgumentError(`${label} must be a positive integer`);\n  }\n  if (typeof max === 'number' && n > max) {\n    throw new ArgumentError(`${label} must be <= ${max}`);\n  }\n  return n;\n}\n\nfunction normalizeNonNegativeInt(value, defaultValue, label, max) {\n  const raw = value ?? defaultValue;\n  const n = Number(raw);\n  if (!Number.isInteger(n) || n < 0) {\n    throw new ArgumentError(`${label} must be a non-negative integer`);\n  }\n  if (typeof max === 'number' && n > max) {\n    throw new ArgumentError(`${label} must be <= ${max}`);\n  }\n  return n;\n}\n\nfunction normalizeDate(value, label) {\n  const v = String(value || '').trim();","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/booking/search.js#L1-L35","documentation":"After confirming the value is a positive integer, normalizePositiveInt checks it against an optional `max` bound. This ArgumentError is thrown when a valid integer exceeds the documented upper limit for that option (e.g. adults > 16, rooms > 8, limit > some cap). It exists to keep search parameters within ranges the underlying provider accepts.","triggerScenarios":"Calling search with e.g. adults: 20, rooms: 10, or limit: 1000 when the respective max caps are lower. The exact bound is stated in the message ('<label> must be <= <max>').","commonSituations":"Bulk/pagination code computing a huge limit; scripts defaulting adults to a large party size; copy-pasted config from another tool with different caps; misunderstanding that 'limit' is unbounded.","solutions":["Read the max value from the error message and pass a value at or below it (e.g. --adults 16).","Clamp programmatically before calling: Math.min(value, MAX).","If you need more results, lower per-call limit and paginate with offset instead of raising limit."],"exampleFix":"// before\nconst limit = 500;\nawait bookingSearch({ limit }); // throws: limit must be <= 50\n// after\nconst limit = Math.min(userLimit, 50);\nawait bookingSearch({ limit });","handlingStrategy":"validation","validationCode":"const LIMITS = { adults: 16, rooms: 8, limit: 50 };\nfunction clampInt(v, label) {\n  const n = Math.max(1, Math.min(Number(v) || 1, LIMITS[label]));\n  if (!Number.isInteger(n)) throw new Error(`${label} invalid`);\n  return n;\n}\nconst limit = clampInt(opts.limit ?? 10, 'limit');","typeGuard":"function isIntWithin(v, max) {\n  return typeof v === 'number' && Number.isInteger(v) && v > 0 && v <= max;\n}","tryCatchPattern":"try {\n  await bookingSearch({ adults, rooms, limit });\n} catch (e) {\n  if (e instanceof ArgumentError && /must be <= \\d+/.test(e.message)) {\n    const max = Number(e.message.match(/<= (\\d+)/)[1]);\n    console.error(`${e.message} — retrying with the max`); // optionally retry clamped\n  } else throw e;\n}","preventionTips":["Keep a table of documented maxima per option and clamp with Math.min.","Prefer pagination (offset) over inflating limit.","Unit-test boundary values (max, max+1) for every capped option.","Surface caps in your own CLI's help text."],"tags":["argument-validation","range-check","cli","bounds"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}