{"record":{"id":"33bba6fe68e3d196","repo":"jackwener/OpenCLI","slug":"pubmed-label-must-be-1800","errorCode":null,"errorMessage":"pubmed ${label} must be >= 1800","messagePattern":"pubmed (.+?) must be >= 1800","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/pubmed/utils.js","lineNumber":48,"sourceCode":"        throw new ArgumentError(`pubmed ${label} must be a positive integer`);\n    }\n    const n = Number(text);\n    if (!Number.isSafeInteger(n) || n < 1) {\n        throw new ArgumentError(`pubmed ${label} must be a positive integer`);\n    }\n    if (n > maxValue) {\n        throw new ArgumentError(`pubmed ${label} must be <= ${maxValue}`);\n    }\n    return n;\n}\n\nexport function requireYear(value, label) {\n    if (value === undefined || value === null || value === '') {\n        return undefined;\n    }\n    const year = requireBoundedInt(value, 1900, 3000, label);\n    if (year < 1800) {\n        throw new ArgumentError(`pubmed ${label} must be >= 1800`);\n    }\n    return year;\n}\n\nexport function requireChoice(value, choices, label, defaultValue) {\n    const text = String(value ?? defaultValue).trim();\n    if (!choices.includes(text)) {\n        throw new ArgumentError(`pubmed ${label} must be one of: ${choices.join(', ')}`);\n    }\n    return text;\n}\n\nexport function buildEutilsUrl(tool, params = {}) {\n    const searchParams = new URLSearchParams();\n    searchParams.set('db', 'pubmed');\n    if (!params.retmode) {\n        searchParams.set('retmode', 'json');\n    }","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pubmed/utils.js#L30-L66","documentation":"requireYear treats year filters as optional (empty passes through as undefined) but otherwise validates via requireBoundedInt and enforces a floor of 1800, since PubMed indexing effectively starts in the 19th century. Years below 1800 throw ArgumentError 'pubmed <label> must be >= 1800' (called by yearFrom/yearTo).","triggerScenarios":"`--year-from 1492`, `--year-to 999`, or any transposed-digit year like 1080 that passes the generic integer checks but is < 1800.","commonSituations":"Typos (1080 vs 1800/1980), using historical or event years that predate PubMed coverage, expecting non-publication dates to work.","solutions":["Use a year >= 1800 (generic checks also cap at 3000)","Double-check for transposed digits","Omit the year filter if it is not needed"],"exampleFix":"// before\n--year-from 1492\n// after\n--year-from 1950","handlingStrategy":"validation","validationCode":"function checkYear(y) {\n  if (y === undefined || y === null || y === '') return undefined;\n  const n = Number(String(y).trim());\n  if (!Number.isSafeInteger(n) || n < 1800 || n > 3000) {\n    throw new Error(`year '${y}' out of range (1800-3000)`);\n  }\n  return n;\n}\ncheckYear(yearFrom);","typeGuard":"function isPlausibleYear(v) {\n  const n = Number(v);\n  return Number.isSafeInteger(n) && n >= 1800 && n <= 3000;\n}","tryCatchPattern":"try {\n  await pubmedSearch(query, { yearFrom, yearTo });\n} catch (err) {\n  if (err instanceof ArgumentError && /must be >= 1800/.test(err.message)) {\n    console.error(`Year '${yearFrom}' predates PubMed coverage; use >= 1800`);\n    process.exitCode = 2;\n  } else { throw err; }\n}","preventionTips":["Check years for transposed digits (1080 vs 1800/1980)","Remember PubMed coverage starts in the 1800s","Omit optional year filters rather than guessing a floor"],"tags":["validation","argument-error","date-range","pubmed"],"backgroundTag":"parameter-out-of-range","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}