{"record":{"id":"c2f0c20435bec7f1","repo":"jackwener/OpenCLI","slug":"limit-must-be-between-1-and-max-search-limit","errorCode":null,"errorMessage":"--limit must be between 1 and ${MAX_SEARCH_LIMIT}, got ${parsed}","messagePattern":"--limit must be between 1 and (.+?), got (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/douyin/search.js","lineNumber":59,"sourceCode":" * skeleton for anonymous visitors, which we surface as AuthRequiredError.\n */\nimport { cli, Strategy } from '@jackwener/opencli/registry';\nimport { ArgumentError, AuthRequiredError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';\n\nexport const MAX_SEARCH_LIMIT = 30;\n// Time budget for the SPA's initial DOM commit. Empirically the\n// scroll-list `<li>` rows appear within 2-4s of navigation when logged\n// in; 15s covers slow networks without blocking on a permanently-empty\n// page (anonymous gate, network error).\nexport const RENDER_TIMEOUT_MS = 15000;\n\nexport function parseSearchLimit(raw) {\n    const parsed = Number(raw ?? 10);\n    if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) {\n        throw new ArgumentError(`--limit must be an integer between 1 and ${MAX_SEARCH_LIMIT}, got ${JSON.stringify(raw)}`);\n    }\n    if (parsed < 1 || parsed > MAX_SEARCH_LIMIT) {\n        throw new ArgumentError(`--limit must be between 1 and ${MAX_SEARCH_LIMIT}, got ${parsed}`);\n    }\n    return parsed;\n}\n\n/**\n * Parse a Douyin display count like \"1.9万\", \"3.1万\", \"4702\", \"1.2亿\"\n * into a plain integer. Returns 0 for unparseable input rather than\n * throwing — the CLI promises numeric columns and missing data is\n * common enough on real result rows that a soft fallback is the right\n * choice.\n */\nexport function parseDouyinCount(text) {\n    if (typeof text !== 'string') return 0;\n    const m = text.replace(/\\s/g, '').match(/^(\\d+(?:\\.\\d+)?)([万亿])?$/);\n    if (!m) {\n        const plain = Number(text.replace(/[,\\s]/g, ''));\n        return Number.isFinite(plain) ? Math.round(plain) : 0;\n    }","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/douyin/search.js#L41-L77","documentation":"The second check in parseSearchLimit: once the value is confirmed a finite integer, it must be within [1, MAX_SEARCH_LIMIT]. Values below 1 or above the maximum throw this ArgumentError with the parsed number. It exists because Douyin's search result page only supports a bounded display count.","triggerScenarios":"Passing --limit 0, a negative number, or an integer greater than MAX_SEARCH_LIMIT (e.g. --limit 500 if the max is 50).","commonSituations":"Users wanting 'all results' guessing an arbitrarily large limit; loop scripts computing limit = total - offset yielding 0 on the last page; off-by-one when a results set is empty.","solutions":["Clamp the value into range before calling: Math.min(Math.max(1, n), MAX_SEARCH_LIMIT)","Page through results with multiple calls using limit <= MAX_SEARCH_LIMIT instead of one large request","Check the library's MAX_SEARCH_LIMIT export for the current bound"],"exampleFix":"// before\nawait douyin.search({ query: 'cats', limit: 500 });\n// after\nconst limit = Math.min(Math.max(1, requested), 50);\nawait douyin.search({ query: 'cats', limit });","handlingStrategy":"validation","validationCode":"const MAX_SEARCH_LIMIT = 50; // import from the library\nfunction clampLimit(raw) {\n  const n = Math.trunc(Number(raw ?? 10));\n  return Math.min(Math.max(1, n), MAX_SEARCH_LIMIT);\n}","typeGuard":"function limitInRange(v, max) {\n  return Number.isInteger(v) && v >= 1 && v <= max;\n}","tryCatchPattern":"try {\n  await douyin.search({ query, limit: rawLimit });\n} catch (e) {\n  if (e instanceof ArgumentError && /must be between 1 and/.test(e.message)) {\n    await douyin.search({ query, limit: clampLimit(rawLimit) });\n  } else throw e;\n}","preventionTips":["Clamp user-supplied limits into [1, MAX_SEARCH_LIMIT] before calling","Page through large result sets with multiple bounded calls","Read MAX_SEARCH_LIMIT from the library instead of hardcoding"],"tags":["validation","argument-error","cli"],"backgroundTag":"invalid-argument-range","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}