{"record":{"id":"af284c222cda0e2b","repo":"jackwener/OpenCLI","slug":"page-must-be-a-positive-integer-got-raw","errorCode":null,"errorMessage":"--page must be a positive integer (got ${raw})","messagePattern":"--page must be a positive integer \\(got (.+?)\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/coupang/utils.js","lineNumber":29,"sourceCode":" */\nexport function parseLimitArg(raw, fallback, max) {\n    if (raw === undefined || raw === null || raw === '') {\n        return fallback;\n    }\n    const num = Number(raw);\n    if (!Number.isInteger(num) || num < 1 || num > max) {\n        throw new ArgumentError(`--limit must be an integer between 1 and ${max} (got ${raw})`);\n    }\n    return num;\n}\n\nexport function parsePageArg(raw, fallback) {\n    if (raw === undefined || raw === null || raw === '') {\n        return fallback;\n    }\n    const num = Number(raw);\n    if (!Number.isInteger(num) || num < 1) {\n        throw new ArgumentError(`--page must be a positive integer (got ${raw})`);\n    }\n    return num;\n}\n\nfunction itemKey(item) {\n    return item.url || item.product_id || `${item.title}:${item.price ?? ''}`;\n}\nconst ROCKET_PATTERNS = ['판매자로켓', '로켓프레시', '로켓와우', '로켓배송', '로켓직구'];\nconst DELIVERY_TYPE_PATTERNS = ['무료배송', '일반배송'];\nconst DELIVERY_PROMISE_PATTERNS = ['오늘도착', '내일도착', '새벽도착', '오늘출발'];\nconst BADGE_ID_TO_ROCKET = {\n    ROCKET: '로켓배송',\n    ROCKET_MERCHANT: '판매자로켓',\n    ROCKET_WOW: '로켓와우',\n    WOW: '로켓와우',\n    ROCKET_FRESH: '로켓프레시',\n    FRESH: '로켓프레시',\n    SELLER_ROCKET: '판매자로켓',","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/coupang/utils.js#L11-L47","documentation":"ArgumentError thrown by parsePageArg when --page is provided but is not an integer >= 1. Like parseLimitArg, it fails fast with the offending value rather than clamping to page 1.","triggerScenarios":"Passing --page as 0, a negative number, a float (2.5), or a non-numeric string while running a paginated coupang search.","commonSituations":"Off-by-one pagination loops starting at 0; computing page from `index` instead of `index + 1`; environment variable interpolation producing 'NaN' or empty garbage.","solutions":["Pass a positive integer (1-based)","Omit --page to use the fallback (page 1)","Fix the loop/index arithmetic producing 0 or negative pages","Validate page values before invoking (Number.isInteger(p) && p >= 1)"],"exampleFix":"// before\n--page 0\n// after\n--page 1","handlingStrategy":"validation","validationCode":"function validPage(raw) { const n = Number(raw); return Number.isInteger(n) && n >= 1 ? n : 1; }","typeGuard":"function isValidPage(v) { return typeof v === 'number' && Number.isInteger(v) && v >= 1; }","tryCatchPattern":"try { await cli.run(['coupang','search', q, '--page', String(page)]); } catch (e) { if (e instanceof ArgumentError && e.message.startsWith('--page')) { page = 1; return retry(); } throw e; }","preventionTips":["Remember pages are 1-based; start loops at 1","Compute page as index + 1, never index","Sanitize numeric env vars before passing them as --page"],"tags":["argument-validation","cli","pagination"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}