{"record":{"id":"26b4302ae91dd97b","repo":"jackwener/OpenCLI","slug":"upwork-label-must-be-a-positive-integer","errorCode":null,"errorMessage":"upwork ${label} must be a positive integer","messagePattern":"upwork (.+?) must be a positive integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/upwork/utils.js","lineNumber":60,"sourceCode":"}\n\nfunction coerceInt(value) {\n    if (value === undefined || value === null || value === '') return NaN;\n    const n = typeof value === 'number' ? value : Number(value);\n    return Number.isFinite(n) && Number.isInteger(n) ? n : NaN;\n}\n\nexport function requireQuery(value, label = 'query') {\n    const q = String(value ?? '').trim();\n    if (!q) throw new ArgumentError(`upwork ${label} cannot be empty`);\n    return q;\n}\n\nexport function requirePositiveInt(value, defaultValue, label) {\n    const raw = value ?? defaultValue;\n    const n = coerceInt(raw);\n    if (!Number.isInteger(n) || n <= 0) {\n        throw new ArgumentError(`upwork ${label} must be a positive integer`);\n    }\n    return n;\n}\n\nexport function requireBoundedInt(value, defaultValue, min, max, label) {\n    const n = requirePositiveInt(value, defaultValue, label);\n    if (n < min) throw new ArgumentError(`upwork ${label} must be >= ${min}`);\n    if (n > max) throw new ArgumentError(`upwork ${label} must be <= ${max}`);\n    return n;\n}\n\n/**\n * Upwork job ids are the ciphertext form starting with `~01` or `~02`\n * (the encoded uid surfaced everywhere in URLs and search results).\n * Accepts a bare ciphertext or a full `/jobs/~02…` URL.\n */\nexport function requireCiphertext(value) {\n    let id = String(value ?? '').trim();","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/upwork/utils.js#L42-L78","documentation":"An ArgumentError thrown by requirePositiveInt when a numeric option (page number, per-page count, etc.) is not a finite integer greater than zero. coerceInt is applied to the raw value (or the default when undefined) and the result must be a positive integer. It guards pagination math against NaN, zero, negatives, and non-numeric strings.","triggerScenarios":"Calling an upwork command with pageNum or n set to 0, a negative number, a non-numeric string like 'abc' or '2.5', or NaN - anything where Number(value) does not yield an integer > 0.","commonSituations":"Passing a float like 1.5 for the page; users supplying 0 or -1 believing pages are zero-indexed; a config file with a string page value; a computed variable that evaluated to NaN before being passed in.","solutions":["Pass a positive integer (1-based) for the option.","Validate/clamp the value before calling: Number.isInteger(n) && n > 0.","If pages are produced from zero-based user input, add 1 before passing.","Fix the upstream computation that is producing NaN or a float."],"exampleFix":"// before\nawait cli.search('react developer', { pageNum: 0 }) // ArgumentError\n// after\nconst pageNum = Math.max(1, Math.trunc(Number(userPage) || 1));\nawait cli.search('react developer', { pageNum })","handlingStrategy":"validation","validationCode":"function toPositiveInt(v) {\n  const n = typeof v === 'number' ? v : Number(v);\n  return Number.isFinite(n) && Number.isInteger(n) && n > 0 ? n : null;\n}\n// before the call:\nconst pageNum = toPositiveInt(rawPage);\nif (pageNum === null) throw new Error('pageNum must be a positive integer');","typeGuard":"function isPositiveInt(v) {\n  return typeof v === 'number' && Number.isInteger(v) && v > 0;\n}","tryCatchPattern":"try {\n  rows = await cli.search(query, { pageNum: rawPage });\n} catch (e) {\n  if (e.name === 'ArgumentError' && String(e.message).includes('positive integer')) {\n    console.error(`Invalid page value: ${JSON.stringify(rawPage)}; use an integer >= 1`);\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Remember pages are 1-based: add 1 to zero-based user input.","Coerce/validate numeric options (Number.isInteger, > 0) at the script boundary.","Reject floats and numeric strings early instead of letting Number() coerce them.","Guard computed values against NaN before passing them as options."],"tags":["argument-validation","pagination","input-validation","upwork"],"backgroundTag":"invalid-numeric-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}