jackwener/OpenCLI · error · CommandExecutionError
semanticscholar recommendations returned an unexpected paylo
Error message
semanticscholar recommendations returned an unexpected payload shape
What it means
The recommendations command (clis/semanticscholar/recommendations.js:39) calls the `/recommendations/v1/papers/forpaper` endpoint and expects a `recommendedPapers` array in the response. If that key is missing or not an array, this CommandExecutionError is thrown because the recommendation payload contract was violated.
Source
Thrown at clis/semanticscholar/recommendations.js:39
access: 'read',
description: 'Semantic Scholar AI-curated related papers for a paperId, DOI, or arXiv id',
domain: 'api.semanticscholar.org',
strategy: Strategy.PUBLIC,
browser: false,
args: [
{ name: 'id', positional: true, required: true, help: 'paperId (40-char hex), DOI, arXiv id, or prefixed id' },
{ name: 'limit', type: 'int', default: 10, help: 'Max recommendations (1-500)' },
],
columns: ['rank', 'paperId', 'doi', 'title', 'year', 'firstAuthor', 'citationCount', 'url'],
func: async (args) => {
const ref = requirePaperRef(args.id);
const limit = requireBoundedInt(args.limit, 10, 500);
const url = `${S2_REC_BASE}/papers/forpaper/${encodeURIComponent(ref)}?fields=${FIELDS}&limit=${limit}`;
const body = await s2Fetch(url, 'semanticscholar recommendations');
const recommended = Array.isArray(body?.recommendedPapers) ? body.recommendedPapers : null;
if (recommended === null) {
throw new CommandExecutionError('semanticscholar recommendations returned an unexpected payload shape');
}
if (!recommended.length) {
throw new EmptyResultError('semanticscholar recommendations', `No Semantic Scholar recommendations for "${args.id}".`);
}
return recommended.slice(0, limit).map((p, i) => normalizePaperRow(p, 'recommendations', { rank: i + 1 }));
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Print the raw response body to see what replaced recommendedPapers.
- Retry with backoff — the recommendations endpoint throttles aggressively and often returns soft errors with 200.
- Confirm the input paper is valid via `semanticscholar paper <id>` first.
- Check the Semantic Scholar recommendations API docs for endpoint/shape changes (it is versioned separately from the graph API).
- Rule out proxies/caches rewriting the response.
Example fix
// before
const body = await s2Fetch(url, 'semanticscholar recommendations');
const recommended = body?.recommendedPapers ?? [];
// after
const body = await s2Fetch(url, 'semanticscholar recommendations');
if (body && typeof body === 'object' && body.error) {
throw new Error(`S2 recommendations soft error: ${body.error} — backoff and retry`);
}
const recommended = Array.isArray(body?.recommendedPapers) ? body.recommendedPapers : []; Defensive patterns
Strategy: type-guard
Validate before calling
function hasRecommendationsEnvelope(body) {
return body !== null && typeof body === 'object' && Array.isArray(body.recommendedPapers);
} Type guard
function isRecommendationsPayload(body) {
return typeof body === 'object' && body !== null && Array.isArray(body.recommendedPapers)
&& body.recommendedPapers.every((p) => p && typeof p === 'object' && 'paperId' in p);
} Try / catch
try {
recs = await recommendations(id);
} catch (err) {
if (/unexpected payload shape/.test(err.message)) {
// recommendations endpoint throttles hard: exponential backoff
await sleep(5000);
recs = await recommendations(id);
} else throw err;
} Prevention
- Rate-limit recommendation calls well below graph-API limits; this endpoint throttles first.
- Validate input paper ids via the paper endpoint before recommending.
- Inspect raw bodies on shape failures — soft throttling errors often lack recommendedPapers.
- Track the recommendations API version separately from the graph API.
When it happens
Trigger: The recommendations endpoint returned 200 with JSON lacking recommendedPapers — e.g. a throttling/soft-error envelope, an error object for an unknown paperId, or an API schema change in the recommendations service.
Common situations: Semantic Scholar rate-limiting the recommendations endpoint (which is stricter than the graph API); recommending from a paper id the service cannot resolve; a proxy or cache substituting its own JSON body; recommendations API version changes.
Related errors
- semanticscholar citations returned an unexpected payload sha
- semanticscholar paper returned an unexpected payload shape
- workspace/create returned no workspace_id: ${JSON.stringify(
- semanticscholar citations row is missing citingPaper
- API_ERROR
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/fb6759b63221af13.
Report an issue: GitHub.