{"record":{"id":"a91d5086c85da777","repo":"jackwener/OpenCLI","slug":"limit-must-be-max-limit","errorCode":null,"errorMessage":"limit must be <= ${MAX_LIMIT}","messagePattern":"limit must be <= (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/aibase/news.js","lineNumber":15,"sourceCode":"import { cli, Strategy } from '@jackwener/opencli/registry';\nimport { ArgumentError, CommandExecutionError, EmptyResultError, getErrorMessage } from '@jackwener/opencli/errors';\n\nconst AIBASE_DAILY_URL = 'https://www.aibase.com/zh/daily';\nconst DEFAULT_LIMIT = 20;\nconst MAX_LIMIT = 50;\n\nfunction normalizeLimit(value) {\n    const raw = value ?? DEFAULT_LIMIT;\n    const limit = Number(raw);\n    if (!Number.isInteger(limit) || limit <= 0) {\n        throw new ArgumentError('limit must be a positive integer', `Example: opencli aibase news --limit ${DEFAULT_LIMIT}`);\n    }\n    if (limit > MAX_LIMIT) {\n        throw new ArgumentError(`limit must be <= ${MAX_LIMIT}`, `Example: opencli aibase news --limit ${MAX_LIMIT}`);\n    }\n    return limit;\n}\n\nfunction normalizeText(value) {\n    return String(value ?? '').replace(/\\s+/g, ' ').trim();\n}\n\nfunction buildExtractAibaseNewsJs() {\n    return `\n      (() => {\n        const anchors = Array.from(document.querySelectorAll('.bg-white .grid a[href], a[href*=\"/zh/daily/\"]'))\n          .filter((anchor) => {\n            const href = anchor.getAttribute('href') || '';\n            const text = (anchor.innerText || anchor.textContent || '').trim();\n            return text && href && !href.endsWith('/zh/daily') && !href.endsWith('/zh/daily/');\n          });\n        if (anchors.length === 0) {","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/aibase/news.js#L1-L33","documentation":"normalizeLimit also caps --limit at MAX_LIMIT (50) and throws an ArgumentError when a valid positive integer exceeds the cap, with an example suggesting --limit 50. This keeps scraping requests bounded so the command doesn't over-fetch or hammer the page.","triggerScenarios":"Running `opencli aibase news --limit 51` or higher (e.g. --limit 100, --limit 1000).","commonSituations":"Users wanting 'all' items passing a large number, scripts using a generic page-size (100) that exceeds this command's max, and confusion with other commands whose limits are uncapped.","solutions":["Use --limit 50 (the maximum) instead.","Omit --limit (default 20) if fewer items suffice.","Note the daily page only exposes a bounded set of articles anyway; there are rarely more than 50 rows to return."],"exampleFix":"// before\nopencli aibase news --limit 100\n// after\nopencli aibase news --limit 50","handlingStrategy":"validation","validationCode":"const n = Number(limitArg);\nif (Number.isInteger(n) && n > 50) throw new Error('--limit max is 50');","typeGuard":"function isWithinCap(v, cap = 50) {\n  return typeof v === 'number' && Number.isInteger(v) && v > 0 && v <= cap;\n}","tryCatchPattern":"try {\n  await runCommand(['aibase', 'news', '--limit', String(n)]);\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.startsWith('limit must be <=')) {\n    await runCommand(['aibase', 'news', '--limit', '50']);\n  } else throw e;\n}","preventionTips":["Clamp page sizes to the command's documented max (50 here)","Don't reuse generic page-size constants (e.g. 100) across commands","Omit --limit to accept the default 20","Remember the daily page has a naturally bounded row count"],"tags":["cli","argument-validation","limits"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}