{"record":{"id":"05cfe61b85c4e12b","repo":"jackwener/OpenCLI","slug":"youtube-search-limit-must-be-a-positive-integer","errorCode":null,"errorMessage":"youtube search limit must be a positive integer","messagePattern":"youtube search limit must be a positive integer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/youtube/search.js","lineNumber":50,"sourceCode":"const SORT_FILTERS = {\n    relevance: '',\n    date: 'CAI%3D',\n    views: 'CAM%3D',\n    rating: 'CAE%3D',\n};\n\nfunction normalizeChoice(value, choices, label) {\n    const normalized = String(value || '').trim();\n    if (normalized && !Object.hasOwn(choices, normalized)) {\n        throw new ArgumentError(`youtube search ${label} must be one of: ${Object.keys(choices).join(', ')}`);\n    }\n    return normalized;\n}\n\nfunction normalizeLimit(value) {\n    const limit = Number(value ?? DEFAULT_LIMIT);\n    if (!Number.isInteger(limit) || limit <= 0) {\n        throw new ArgumentError('youtube search limit must be a positive integer');\n    }\n    if (limit > MAX_LIMIT) {\n        throw new ArgumentError(`youtube search limit must be <= ${MAX_LIMIT}`);\n    }\n    return limit;\n}\n\ncli({\n    site: 'youtube',\n    name: 'search',\n    access: 'read',\n    description: 'Search YouTube videos, Shorts, channels, and playlists',\n    domain: 'www.youtube.com',\n    strategy: Strategy.COOKIE,\n    args: [\n        { name: 'query', required: true, positional: true, help: 'Search query' },\n        { name: 'limit', type: 'int', default: DEFAULT_LIMIT, help: 'Max results (max 50)' },\n        { name: 'type', default: '', help: 'Filter type: shorts, video, channel, playlist' },","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/youtube/search.js#L32-L68","documentation":"ArgumentError from normalizeLimit rejecting a --limit that is not a positive integer. The value is coerced with Number(value ?? 20); non-numeric strings become NaN and decimals fail the Number.isInteger check, so anything <= 0, NaN, or Infinity throws before the request is made.","triggerScenarios":"`--limit 0`, `--limit -5`, `--limit abc`, `--limit 10.5`, `--limit \"\"` (empty string coerces to 0), or a script passing null/undefined in a way that coerces to NaN.","commonSituations":"Off-by-one loops generating 0, shell variables that are empty or contain whitespace/newlines, config files with string limits like \"25 items\", or float division results passed straight through.","solutions":["Pass an integer between 1 and 50, e.g. --limit 20","Sanitize shell/config values: trim, Number() them, and check Number.isInteger(n) && n > 0 before calling","Omit --limit to use the default of 20"],"exampleFix":"// before\nopencli youtube search \"cats\" --limit \"${COUNT}\"  // COUNT empty -> 0\n// after\nLIMIT=${COUNT:-20}; opencli youtube search \"cats\" --limit \"$LIMIT\"","handlingStrategy":"validation","validationCode":"function normalizeLimit(value, { DEFAULT = 20, MAX = 50 } = {}) {\n  const n = Number(value ?? DEFAULT);\n  if (!Number.isInteger(n) || n <= 0) throw new Error(`limit must be a positive integer, got: ${JSON.stringify(value)}`);\n  return Math.min(n, MAX);\n}","typeGuard":"const isValidLimit = (v) => Number.isInteger(Number(v)) && Number(v) > 0;","tryCatchPattern":"try {\n  await run('youtube search', [query, '--limit', String(limit)]);\n} catch (e) {\n  if (/limit must be a positive integer/i.test(e.message)) {\n    console.error(`Invalid --limit ${limit}; using default 20`);\n    return run('youtube search', [query]);\n  }\n  throw e;\n}","preventionTips":["Sanitize shell/config values with Number() before passing","Guard against empty strings (coerce to 0) from unset env vars","Always pass limits via String(n) to avoid formatting surprises","Fall back to the default 20 when the value is unusable"],"tags":["youtube","search","argument-validation","cli"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}