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

  1. Print the raw response body to see what replaced recommendedPapers.
  2. Retry with backoff — the recommendations endpoint throttles aggressively and often returns soft errors with 200.
  3. Confirm the input paper is valid via `semanticscholar paper <id>` first.
  4. Check the Semantic Scholar recommendations API docs for endpoint/shape changes (it is versioned separately from the graph API).
  5. 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

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


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/fb6759b63221af13. Report an issue: GitHub.