jackwener/OpenCLI · error · CommandExecutionError
semanticscholar search returned an unexpected payload shape
Error message
semanticscholar search returned an unexpected payload shape
What it means
The Semantic Scholar /paper/search endpoint is expected to return an object with a `data` array of paper results. This library throws a CommandExecutionError when the response JSON either is not an object or lacks an array-shaped `data` field, i.e. the payload does not match the documented Graph API search schema. It guards callers from dereferencing `body.data` on a malformed or schema-changed response.
Source
Thrown at clis/semanticscholar/search.js:40
access: 'read',
description: 'Search Semantic Scholar papers by free text',
domain: 'api.semanticscholar.org',
strategy: Strategy.PUBLIC,
browser: false,
args: [
{ name: 'query', positional: true, required: true, help: 'Search text (e.g. "attention is all you need", "diffusion model")' },
{ name: 'limit', type: 'int', default: 20, help: 'Max papers (1-100, single Semantic Scholar page)' },
],
columns: ['rank', 'paperId', 'doi', 'title', 'year', 'firstAuthor', 'citationCount', 'url'],
func: async (args) => {
const query = requireString(args.query, 'query');
const limit = requireBoundedInt(args.limit, 20, 100);
const url = `${S2_GRAPH_BASE}/paper/search?query=${encodeURIComponent(query)}&limit=${limit}&fields=${FIELDS}`;
const body = await s2Fetch(url, 'semanticscholar search');
const data = Array.isArray(body?.data) ? body.data : null;
if (data === null) {
throw new CommandExecutionError('semanticscholar search returned an unexpected payload shape');
}
if (!data.length) {
throw new EmptyResultError('semanticscholar search', `No Semantic Scholar papers matched "${query}".`);
}
return data.slice(0, limit).map((p, i) => normalizePaperRow(p, 'search', { rank: i + 1 }));
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Log the raw response body (e.g. curl the same URL with your SEMANTIC_SCHOLAR_API_KEY) and inspect the actual JSON shape to see what deviated.
- Check status.semanticscholar.org / the Graph API changelog for a schema change to /paper/search and update the adapter or library.
- Retry after a short wait if a transient gateway was substituting error bodies; verify network path to api.semanticscholar.org.
- If a proxy is rewriting responses, bypass it or add it to NO_PROXY so the client talks to the API directly.
Example fix
// before
const data = Array.isArray(body?.data) ? body.data : null;
if (data === null) {
throw new CommandExecutionError('semanticscholar search returned an unexpected payload shape');
}
// after (log the offending payload to debug)
const data = Array.isArray(body?.data) ? body.data : null;
if (data === null) {
throw new CommandExecutionError(
`semanticscholar search returned an unexpected payload shape: ${JSON.stringify(body).slice(0, 300)}`,
);
} Defensive patterns
Strategy: type-guard
Type guard
function isSearchPayload(body) {
return body != null && typeof body === 'object' && Array.isArray(body.data);
}
// usage: if (!isSearchPayload(body)) throw new CommandExecutionError('unexpected payload shape'); Try / catch
try {
const rows = await searchPapers(query);
} catch (err) {
if (err instanceof CommandExecutionError && /unexpected payload shape/.test(err.message)) {
logger.error('S2 search schema drift', err.message);
} else throw err;
} Prevention
- Pin and monitor the Graph API version you target; subscribe to Semantic Scholar API announcements.
- Log raw response bodies on schema mismatch so drift is diagnosable.
- Add a contract test that mocks /paper/search and asserts the `data` array shape.
- Bypass intercepting proxies for API hosts to avoid shape-rewriting middleware.
When it happens
Trigger: Calling `opencli semanticscholar search <query>` when the API responds 200 with JSON whose `data` property is missing, null, or not an array (e.g. an error envelope like `{message, error}` slipped past body.error checks, a proxy returned a different JSON shape, or Semantic Scholar changed the search response schema).
Common situations: Corporate proxies or captive portals injecting JSON error bodies; Semantic Scholar returning an API-level error object with a 200 status; API version drift (Graph v1 schema change); hitting a mirror/gateway that does not proxy the Graph API faithfully.
Related errors
- ${label} returned HTTP ${resp.status}: ${summarizeApiError(p
- arXiv API HTTP ${resp.status}
- Bilibili ${label} API returned a malformed payload
- 获取视频分P信息失败: ${error?.message || error}
- 获取视频信息失败: ${err?.message || err}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/47c2013bf75e8dc2.
Report an issue: GitHub.