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

  1. Log/print the raw response body to see what the API actually returned instead of {data: [...]} .
  2. Retry after a delay — Semantic Scholar frequently returns soft error bodies with 200 when throttled.
  3. Verify the paper id/DOI/arXiv ref is valid (test with `semanticscholar paper <id>`).
  4. Check Semantic Scholar API status/changelog for a response-shape change and update the adapter.
  5. 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

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


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