{"record":{"id":"21c6d388a9878b84","repo":"jackwener/OpenCLI","slug":"linkedin-learning-searchv2-returned-no-parseable-r","errorCode":null,"errorMessage":"LinkedIn Learning searchV2 returned no parseable rows with slug identity","messagePattern":"LinkedIn Learning searchV2 returned no parseable rows with slug identity","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin-learning/search.js","lineNumber":88,"sourceCode":"        const result = await fetchLinkedInLearningApi(page, url);\n        if (!result?.json) {\n            throw new CommandExecutionError(`LinkedIn Learning searchV2 failed: ${result?.error ?? 'no payload'}`);\n        }\n        const elements = result.json?.elements;\n        if (!Array.isArray(elements)) {\n            throw new CommandExecutionError('LinkedIn Learning searchV2 returned malformed payload: missing elements array');\n        }\n        if (elements.length === 0) {\n            throw new EmptyResultError(`No LinkedIn Learning results for \"${keywords}\"`);\n        }\n        const rows = [];\n        for (const el of elements) {\n            if (rows.length >= limit) break;\n            const row = parseRow(el, rows.length + 1);\n            if (row) rows.push(row);\n        }\n        if (rows.length === 0) {\n            throw new CommandExecutionError('LinkedIn Learning searchV2 returned no parseable rows with slug identity');\n        }\n        return rows;\n    },\n});\n\nexport const __test__ = {\n    parseAuthors,\n    durationSeconds,\n    averageRating,\n    parseRow,\n};\n","sourceCodeStart":70,"sourceCodeEnd":100,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin-learning/search.js#L70-L100","documentation":"Thrown after iterating the searchV2 elements when zero rows could be parsed into records carrying a slug identity. Unlike the empty-elements case, elements existed but every element failed parseRow — meaning the per-element shape changed or lacks the identity fields the parser keys on.","triggerScenarios":"All elements in the payload lack the fields parseRow needs to extract a course slug/identity (e.g. LinkedIn renamed entity subtypes, moved 'lockedValue'/'title'/'slug' fields, or elements contain only sponsored/ads entries).","commonSituations":"LinkedIn Learning schema drift in element structure (new entity version), a payload consisting entirely of non-course elements, or an outdated CLI parser lagging behind the current API shape.","solutions":["Dump one raw element (result.json.elements[0]) and compare its shape to parseRow's expectations.","Update the CLI to a version whose parseRow matches the current searchV2 element schema.","Extend parseRow to handle the new element shape while preserving slug identity extraction.","Confirm via the web UI that normal course results exist for the query (rules out an all-ads payload)."],"exampleFix":"// before\nconst row = parseRow(el, rows.length + 1);\n// after\nconst row = parseRow(el, rows.length + 1) ?? parseRowV2(el, rows.length + 1);","handlingStrategy":"type-guard","validationCode":"// verify at least one element carries identifiable fields before parsing\nconst identifiable = elements.filter(el => el && (el.slug || el.entityUrn || el.title));\nif (identifiable.length === 0) throw new Error('No identifiable course elements in payload');","typeGuard":"function hasSlugIdentity(el) {\n  return !!el && typeof el === 'object' &&\n    typeof (el.slug ?? el.entityUrn) === 'string' && (el.slug ?? el.entityUrn).length > 0;\n}","tryCatchPattern":"try {\n  const rows = await search(page, { keywords });\n} catch (e) {\n  if (e.message.includes('no parseable rows')) {\n    console.error('Element schema changed; dump elements[0] and update parseRow');\n  } else throw e;\n}","preventionTips":["Periodically inspect a raw searchV2 element against parseRow's expectations","Update the CLI when LinkedIn changes element entity structure","Support multiple parser variants to absorb schema drift","Alert on this error — it usually means an API schema change, not bad input"],"tags":["schema","parsing","linkedin","payload"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}