{"record":{"id":"20b679060c90074c","repo":"jackwener/OpenCLI","slug":"pubmed-year-from-must-be-year-to-20b679","errorCode":null,"errorMessage":"pubmed year-from must be <= year-to","messagePattern":"pubmed year-from must be <= year-to","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/pubmed/utils.js","lineNumber":256,"sourceCode":"            return null;\n        }\n        return summaryToRow(article, index + 1, pmid);\n    });\n    if (rows.some(row => row === null)) {\n        throw new CommandExecutionError(`${commandLabel} omitted summaries for one or more PMIDs`, 'Refusing to return a partial result set.');\n    }\n    return rows;\n}\n\nexport function buildSearchQuery(query, filters = {}) {\n    const terms = [requireText(query, 'query')];\n    if (filters.author) terms.push(`${requireText(filters.author, 'author')}[Author]`);\n    if (filters.journal) terms.push(`${requireText(filters.journal, 'journal')}[Journal]`);\n    if (filters.yearFrom || filters.yearTo) {\n        const from = filters.yearFrom || 1800;\n        const to = filters.yearTo || new Date().getFullYear();\n        if (from > to) {\n            throw new ArgumentError('pubmed year-from must be <= year-to');\n        }\n        terms.push(`${from}:${to}[PDAT]`);\n    }\n    if (filters.articleType) terms.push(`${requireText(filters.articleType, 'article-type')}[PT]`);\n    if (filters.hasAbstract) terms.push('hasabstract[text]');\n    if (filters.hasFullText) terms.push('free full text[sb]');\n    if (filters.humanOnly) terms.push('humans[mesh]');\n    if (filters.englishOnly) terms.push('english[lang]');\n    return terms.join(' AND ');\n}\n\nexport function parseArticleXml(xml, pmid) {\n    const text = String(xml ?? '');\n    if (!text || /<ERROR\\b/i.test(text) || !/<PubmedArticle\\b/i.test(text)) {\n        return null;\n    }\n    const returnedPmid = extractFirst(text, 'PMID');\n    if (!returnedPmid) {","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pubmed/utils.js#L238-L274","documentation":"buildSearchQuery validates the optional year range filters before constructing the PubMed PDAT date-range term. If filters.yearFrom exceeds filters.yearTo it throws ArgumentError 'pubmed year-from must be <= year-to'. The library throws this up front because an inverted range would silently produce an empty/meaningless query.","triggerScenarios":"Calling searchQuery (or any search entry point) with filters like { yearFrom: 2024, yearTo: 2020 } — from greater than to. Defaults apply when only one bound is given (from defaults to 1800, to defaults to current year), so the error only fires when both are explicitly set and inverted.","commonSituations":"Swapping the from/to arguments by mistake; UI or script passing dates in the wrong order; programmatically building ranges where variables got mixed up.","solutions":["Swap the values so yearFrom <= yearTo in the caller","Validate the range before invoking: if (from > to) swap or reject","Check for argument-order mistakes where the filter object was constructed"],"exampleFix":"// before\nawait searchQuery(q, { yearFrom: 2024, yearTo: 2020 });\n// after\nconst from = Math.min(2024, 2020), to = Math.max(2024, 2020);\nawait searchQuery(q, { yearFrom: from, yearTo: to });","handlingStrategy":"validation","validationCode":"// Validate the year range before calling searchQuery\nfunction checkYearRange(filters) {\n  const from = filters.yearFrom ?? 1800;\n  const to = filters.yearTo ?? new Date().getFullYear();\n  if (from > to) throw new Error('yearFrom must be <= yearTo');\n}\ncheckYearRange({ yearFrom: 2024, yearTo: 2020 }); // throws early","typeGuard":null,"tryCatchPattern":"try {\n  const q = await searchQuery(query, filters);\n} catch (e) {\n  if (/year-from must be <= year-to/.test(e.message)) {\n    [filters.yearFrom, filters.yearTo] = [filters.yearTo, filters.yearFrom];\n    return searchQuery(query, filters); // auto-correct and retry\n  }\n  throw e;\n}","preventionTips":["Always validate from <= to in UI/scripts that collect year ranges","Normalize the range (Math.min/Math.max) before passing filters","Watch argument order when constructing filter objects programmatically","Add unit tests covering inverted date ranges"],"tags":["validation","argument-error","pubmed","date-range"],"backgroundTag":"invalid-parameter-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}