jackwener/OpenCLI · error · CommandExecutionError
semanticscholar citations returned an unexpected payload sha
Error message
semanticscholar citations returned an unexpected payload shape
What it means
After a successful s2Fetch, the citations command (clis/semanticscholar/citations.js:48) expects the Semantic Scholar `/paper/{ref}/citations` payload to contain a `data` array. If `body.data` is missing or not an array, it throws this CommandExecutionError because the response cannot be interpreted as a citations page.
Source
Thrown at clis/semanticscholar/citations.js:48
],
columns: ['rank', 'paperId', 'doi', 'title', 'year', 'firstAuthor', 'citationCount', 'url'],
func: async (args) => {
const ref = requirePaperRef(args.id);
const limit = requireBoundedInt(args.limit, 20, 1000);
const offsetRaw = args.offset ?? 0;
const offset = typeof offsetRaw === 'number' ? offsetRaw : Number(offsetRaw);
if (!Number.isInteger(offset) || offset < 0) {
throw new ArgumentError('semanticscholar citations offset must be a non-negative integer');
}
if (offset > 9999) {
throw new ArgumentError('semanticscholar citations offset must be <= 9999');
}
const url = `${S2_GRAPH_BASE}/paper/${encodeURIComponent(ref)}/citations?fields=${FIELDS}&limit=${limit}&offset=${offset}`;
const body = await s2Fetch(url, 'semanticscholar citations');
const data = Array.isArray(body?.data) ? body.data : null;
if (data === null) {
throw new CommandExecutionError('semanticscholar citations returned an unexpected payload shape');
}
if (!data.length) {
throw new EmptyResultError('semanticscholar citations', `No Semantic Scholar citations for "${args.id}" at offset ${offset}.`);
}
return data.slice(0, limit).map((entry, i) => {
if (!entry || typeof entry !== 'object' || !('citingPaper' in entry)) {
throw new CommandExecutionError('semanticscholar citations row is missing citingPaper');
}
return normalizePaperRow(entry.citingPaper, 'citations', { rank: offset + i + 1 });
});
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Log/print the raw response body to see what the API actually returned instead of {data: [...]} .
- Retry after a delay — Semantic Scholar frequently returns soft error bodies with 200 when throttled.
- Verify the paper id/DOI/arXiv ref is valid (test with `semanticscholar paper <id>`).
- Check Semantic Scholar API status/changelog for a response-shape change and update the adapter.
- Check whether an intermediary (proxy) is substituting its own JSON error payload.
Example fix
// before
const body = await s2Fetch(url, 'semanticscholar citations');
// after
const body = await s2Fetch(url, 'semanticscholar citations');
if (body && typeof body === 'object' && body.error) {
throw new Error(`S2 soft error: ${body.error} — retry later`);
}
// then proceed to body.data handling Defensive patterns
Strategy: type-guard
Validate before calling
// Validate the envelope as soon as you have the body:
function hasCitationsEnvelope(body) {
return body !== null && typeof body === 'object' && Array.isArray(body.data);
} Type guard
function isCitationsPayload(body) {
return typeof body === 'object' && body !== null
&& Array.isArray(body.data)
&& body.data.every((e) => e && typeof e === 'object' && 'citingPaper' in e);
} Try / catch
try {
rows = await citations(id, offset);
} catch (err) {
if (/unexpected payload shape/.test(err.message)) {
await sleep(1000);
rows = await citations(id, offset); // soft-error bodies with 200 are often transient
} else throw err;
} Prevention
- Log the raw response body when the shape check fails to diagnose soft errors.
- Back off and retry once before surfacing the failure to users.
- Pin/track the Semantic Scholar API version you depend on and watch its changelog.
- Keep validation of body.data centralized in one helper so schema drift is caught in one place.
When it happens
Trigger: The API returned 200 with JSON that is not the expected envelope — e.g. an error object like {error: "..."} or {message: "..."} served with 200, a rate-limit/throttling body, or an API schema change where citations are keyed differently.
Common situations: Semantic Scholar serving soft errors (throttling or maintenance notices) with HTTP 200; hitting an API version whose response shape changed; a proxy returning its own JSON error document; using an unsupported paper reference that yields an error envelope.
Related errors
- semanticscholar paper returned an unexpected payload shape
- semanticscholar recommendations returned an unexpected paylo
- workspace/create returned no workspace_id: ${JSON.stringify(
- semanticscholar citations row is missing citingPaper
- Bilibili user search returned malformed result for ${input}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/3222c17c7f7e88cf.
Report an issue: GitHub.