jackwener/OpenCLI · error · CommandExecutionError
semanticscholar ${label} row is not an object
Error message
semanticscholar ${label} row is not an object What it means
normalizePaperRow asserts each result row from the Semantic Scholar API is a non-null object before extracting fields. When a row is null, an array element that is a string, or otherwise not an object, it throws this CommandExecutionError. It protects downstream field access from TypeError crashes.
Source
Thrown at clis/semanticscholar/utils.js:164
if (!Array.isArray(authors) || !authors.length) return '';
const first = authors[0];
if (first && typeof first === 'object' && typeof first.name === 'string') {
return first.name.trim();
}
return '';
}
export function optionalNumber(value, label) {
if (value == null) return null;
if (typeof value !== 'number' || !Number.isFinite(value)) {
throw new CommandExecutionError(`semanticscholar ${label} must be a number when present`);
}
return value;
}
export function normalizePaperRow(paper, label, { rank } = {}) {
if (!paper || typeof paper !== 'object') {
throw new CommandExecutionError(`semanticscholar ${label} row is not an object`);
}
if (typeof paper.paperId !== 'string' || !paper.paperId.trim()) {
throw new CommandExecutionError(`semanticscholar ${label} row is missing paperId`);
}
if (typeof paper.title !== 'string' || !paper.title.trim()) {
throw new CommandExecutionError(`semanticscholar ${label} row is missing title`);
}
if (paper.authors != null && !Array.isArray(paper.authors)) {
throw new CommandExecutionError(`semanticscholar ${label} row has malformed authors`);
}
const row = {
paperId: paper.paperId.trim(),
doi: pickDoi(paper.externalIds),
title: paper.title.trim(),
year: optionalNumber(paper.year, `${label} year`),
firstAuthor: firstAuthorName(paper.authors),
citationCount: optionalNumber(paper.citationCount, `${label} citationCount`),
url: typeof paper.url === 'string' && paper.url.trim()View on GitHub (pinned to 49907e53dc)
Solutions
- Filter the raw list before normalizing: rows.filter(r => r && typeof r === 'object').
- Inspect the endpoint's raw JSON to confirm whether nulls are expected (deleted papers).
- Wrap normalization per-row and skip/report bad rows instead of failing the whole command.
- Retry — transient backend corruption can produce null rows.
Example fix
// before const rows = data.data.map(p => normalizePaperRow(p, 'citation')); // after const rows = data.data.filter(p => p && typeof p === 'object').map(p => normalizePaperRow(p, 'citation'));
Defensive patterns
Strategy: type-guard
Validate before calling
const safeRows = (data.data ?? []).filter(r => r && typeof r === 'object');
Type guard
function isPaperRow(v) {
return v !== null && typeof v === 'object' && !Array.isArray(v);
} Try / catch
try {
const rows = data.data.map(p => normalizePaperRow(p, 'citation'));
} catch (err) {
if (/row is not an object/.test(err.message)) {
const rows = data.data.filter(isPaperRow).map(p => normalizePaperRow(p, 'citation'));
return rows;
}
throw err;
} Prevention
- Always filter raw result lists for object entries before normalizing.
- Expect null placeholders for deleted/merged S2 papers in citation lists.
- Normalize per-row inside try/catch so one bad row doesn't kill the batch.
When it happens
Trigger: An endpoint (citations, references, recommendations) returns a list containing null or non-object entries where paper objects are expected, and normalizePaperRow is called on such an entry.
Common situations: Semantic Scholar returning null placeholders for deleted/merged papers inside citation lists; recommendations API emitting sparse rows; mock/stub data used in scripts.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- semanticscholar ${label} row has malformed authors
- semanticscholar ${label} must be a number when present
- semanticscholar ${label} row is missing paperId
- semanticscholar ${label} row is missing title
- ${label} must be an integer between ${min} and ${max}, got $
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/bc655eac98d203eb.
Report an issue: GitHub.