{"record":{"id":"a0436fe967efe335","repo":"jackwener/OpenCLI","slug":"pubmed-review-did-not-return-an-id-list","errorCode":null,"errorMessage":"pubmed review did not return an id list","messagePattern":"pubmed review did not return an id list","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/pubmed/review.js","lineNumber":51,"sourceCode":"        const limit = requireBoundedInt(args.limit, 20, 100);\n        const yearFrom = requireYear(args['year-from'], 'year-from');\n        const yearTo = requireYear(args['year-to'], 'year-to');\n        const sort = requireChoice(args.sort, ['date', 'relevance'], 'sort', 'date');\n        const searchQuery = buildSearchQuery(query, {\n            yearFrom,\n            yearTo,\n            articleType: 'Review',\n            hasAbstract: args['has-abstract'],\n        });\n        const esearch = await eutilsFetch('esearch', {\n            term: searchQuery,\n            retmax: limit,\n            usehistory: 'y',\n            sort: sort === 'date' ? 'pub_date' : '',\n        }, { label: 'pubmed review' });\n        const pmids = esearch?.esearchresult?.idlist;\n        if (!Array.isArray(pmids)) {\n            throw new CommandExecutionError('pubmed review did not return an id list', 'PubMed ESearch response shape may have changed.');\n        }\n        if (pmids.length === 0) {\n            throw new EmptyResultError('pubmed review', `No review articles matched \"${query}\".`);\n        }\n        return fetchSummaryRows(pmids, 'pubmed review summary');\n    },\n});\n","sourceCodeStart":33,"sourceCodeEnd":59,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pubmed/review.js#L33-L59","documentation":"This CommandExecutionError is thrown when the ESearch response for `pubmed review` has no valid `esearchresult.idlist` array. The library validates the response shape before reading results, so a malformed or error body (rate limit, downtime, schema change) surfaces as this explicit error instead of a TypeError downstream.","triggerScenarios":"NCBI returns an error payload in esearchresult (invalid query syntax in the constructed review-filtered query), rate limiting, eutilsFetch resolves to null/undefined, or the ESearch response schema changes.","commonSituations":"Requests exceeding NCBI's anonymous rate limit; NCBI maintenance; malformed quotes/brackets in the user query that propagate into the API term; misconfigured proxy altering responses.","solutions":["Retry after a pause; transient API errors are the top cause","Add an NCBI api_key and keep to <=3 requests/second","Check the user query for unbalanced quotes/brackets that would make ESearch return an error object","Inspect the raw response to confirm whether the schema changed and update accordingly"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const res = await eutilsFetch('esearch', { term, retmax: 0 }, { label: 'probe' });\nif (res?.esearchresult?.ERROR) throw new Error(`bad query: ${res.esearchresult.ERROR}`);\nif (!Array.isArray(res?.esearchresult?.idlist)) console.error('unexpected ESearch body');","typeGuard":"function hasIdlist(res) {\n  return Array.isArray(res?.esearchresult?.idlist);\n}","tryCatchPattern":"try {\n  return await clis.pubmedReview({ query, limit });\n} catch (e) {\n  if (e.name === 'CommandExecutionError' && /did not return an id list/.test(e.message)) {\n    await backoff(); // retry once; escalate with raw response if it repeats\n    return retryOnce();\n  }\n  throw e;\n}","preventionTips":["Sanitize user queries (balanced quotes, valid field tags) before they reach ESearch","Use an api_key and respect the 3 req/sec limit","Centralize ESearch shape validation in one helper shared across commands","Watch NCBI E-utilities announcements for response schema changes"],"tags":["network","api-response","pubmed","schema-change"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}