{"record":{"id":"bc655eac98d203eb","repo":"jackwener/OpenCLI","slug":"semanticscholar-label-row-is-not-an-object","errorCode":null,"errorMessage":"semanticscholar ${label} row is not an object","messagePattern":"semanticscholar (.+?) row is not an object","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/semanticscholar/utils.js","lineNumber":164,"sourceCode":"    if (!Array.isArray(authors) || !authors.length) return '';\n    const first = authors[0];\n    if (first && typeof first === 'object' && typeof first.name === 'string') {\n        return first.name.trim();\n    }\n    return '';\n}\n\nexport function optionalNumber(value, label) {\n    if (value == null) return null;\n    if (typeof value !== 'number' || !Number.isFinite(value)) {\n        throw new CommandExecutionError(`semanticscholar ${label} must be a number when present`);\n    }\n    return value;\n}\n\nexport function normalizePaperRow(paper, label, { rank } = {}) {\n    if (!paper || typeof paper !== 'object') {\n        throw new CommandExecutionError(`semanticscholar ${label} row is not an object`);\n    }\n    if (typeof paper.paperId !== 'string' || !paper.paperId.trim()) {\n        throw new CommandExecutionError(`semanticscholar ${label} row is missing paperId`);\n    }\n    if (typeof paper.title !== 'string' || !paper.title.trim()) {\n        throw new CommandExecutionError(`semanticscholar ${label} row is missing title`);\n    }\n    if (paper.authors != null && !Array.isArray(paper.authors)) {\n        throw new CommandExecutionError(`semanticscholar ${label} row has malformed authors`);\n    }\n    const row = {\n        paperId: paper.paperId.trim(),\n        doi: pickDoi(paper.externalIds),\n        title: paper.title.trim(),\n        year: optionalNumber(paper.year, `${label} year`),\n        firstAuthor: firstAuthorName(paper.authors),\n        citationCount: optionalNumber(paper.citationCount, `${label} citationCount`),\n        url: typeof paper.url === 'string' && paper.url.trim()","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/semanticscholar/utils.js#L146-L182","documentation":"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.","triggerScenarios":"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.","commonSituations":"Semantic Scholar returning null placeholders for deleted/merged papers inside citation lists; recommendations API emitting sparse rows; mock/stub data used in scripts.","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."],"exampleFix":"// before\nconst rows = data.data.map(p => normalizePaperRow(p, 'citation'));\n// after\nconst rows = data.data.filter(p => p && typeof p === 'object').map(p => normalizePaperRow(p, 'citation'));","handlingStrategy":"type-guard","validationCode":"const safeRows = (data.data ?? []).filter(r => r && typeof r === 'object');","typeGuard":"function isPaperRow(v) {\n  return v !== null && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  const rows = data.data.map(p => normalizePaperRow(p, 'citation'));\n} catch (err) {\n  if (/row is not an object/.test(err.message)) {\n    const rows = data.data.filter(isPaperRow).map(p => normalizePaperRow(p, 'citation'));\n    return rows;\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["validation","type-error","data-shape","semantic-scholar"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}