{"record":{"id":"61abfb5b624d51ba","repo":"jackwener/OpenCLI","slug":"linkedin-learning-feedrecommendationgroups-failed","errorCode":null,"errorMessage":"LinkedIn Learning feedRecommendationGroups failed: ${result?.error ?? 'no payload'}","messagePattern":"LinkedIn Learning feedRecommendationGroups failed: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin-learning/trending.js","lineNumber":46,"sourceCode":"    site: 'linkedin-learning',\n    name: 'trending',\n    access: 'read',\n    description: 'Browse LinkedIn Learning recommended courses across personalized carousels',\n    domain: DOMAIN,\n    strategy: Strategy.COOKIE,\n    browser: true,\n    args: [\n        { name: 'limit', type: 'int', default: 10, help: `Maximum results to return (1-${MAX_LIMIT})` },\n    ],\n    columns: ['rank', 'group', 'type', 'title', 'difficulty', 'viewers', 'url'],\n    func: async (page, args) => {\n        if (!page) throw new CommandExecutionError('Browser session required for linkedin-learning trending');\n        const limit = parseLimit(args.limit);\n\n        const url = `https://www.linkedin.com/learning-api/feedRecommendationGroups?countPerCarousel=${MAX_PER_CAROUSEL}&q=learner`;\n        const result = await fetchLinkedInLearningApi(page, url);\n        if (!result?.json) {\n            throw new CommandExecutionError(`LinkedIn Learning feedRecommendationGroups failed: ${result?.error ?? 'no payload'}`);\n        }\n        const groups = result.json?.elements;\n        if (!Array.isArray(groups)) {\n            throw new CommandExecutionError('LinkedIn Learning feedRecommendationGroups returned malformed payload: missing elements array');\n        }\n        const rows = [];\n        const seen = new Set();\n        let rank = 1;\n        let sawCards = false;\n        for (const group of groups) {\n            const carousels = Array.isArray(group?.carousels) ? group.carousels : [];\n            for (const carousel of carousels) {\n                const cards = Array.isArray(carousel?.cards) ? carousel.cards : [];\n                for (const card of cards) {\n                    sawCards = true;\n                    if (rows.length >= limit) break;\n                    const slug = card?.slug;\n                    if (!slug || seen.has(slug)) continue;","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin-learning/trending.js#L28-L64","documentation":"Thrown when the feedRecommendationGroups API call finishes but yields no JSON payload (result.json absent), mirroring the searchV2 case. The in-page fetch script reports the cause in result.error (HTTP status or fetch failure); 'no payload' means even the error field was missing.","triggerScenarios":"The in-page fetch throws (network error, aborted navigation) returning {error:'fetch failed: ...'}, or the endpoint responds with a non-OK status other than 401/403 (e.g. HTTP 429/500), yielding {error:'HTTP <status>'} instead of {json}.","commonSituations":"LinkedIn throttling the feed API for the session, transient 5xx outages, session soft-expiring with a redirect that isn't 401/403, or navigating the page away during page.evaluate.","solutions":["Retry after a delay (429/5xx are typically transient).","Re-authenticate in the browser if the session appears stale.","Inspect result.error in the message for the HTTP status and act accordingly (backoff for 429).","Update the CLI if LinkedIn changed the feedRecommendationGroups endpoint.","Check network/proxy connectivity for the automated browser."],"exampleFix":"// before\nif (!result?.json) throw new CommandExecutionError(`feedRecommendationGroups failed: ${result?.error ?? 'no payload'}`);\n// after\nif (!result?.json) {\n  if (result?.error === 'HTTP 429') await sleep(60000);\n  throw new CommandExecutionError(`feedRecommendationGroups failed: ${result?.error ?? 'no payload'}`);\n}","handlingStrategy":"try-catch","validationCode":"// confirm session before calling trending API\nconst cookies = await page.getCookies({ url: 'https://www.linkedin.com' });\nif (!cookies.some(c => c.name === 'JSESSIONID')) throw new Error('Sign in to LinkedIn first');","typeGuard":"function hasJson(r) { return !!r && typeof r === 'object' && r.json !== null && typeof r.json === 'object'; }","tryCatchPattern":"try {\n  const rows = await trending(page);\n} catch (e) {\n  if (/HTTP 429/.test(e.message)) { await sleep(60000); /* back off and retry */ }\n  else if (/auth/i.test(e.message)) { await relogin(page); }\n  else throw e;\n}","preventionTips":["Throttle trending calls to avoid LinkedIn feed-API rate limits","Refresh the session when errors indicate stale auth","Retry transient 5xx with exponential backoff","Keep the CLI updated for feedRecommendationGroups endpoint changes"],"tags":["network","api","http","linkedin"],"backgroundTag":"upstream-api-non-ok-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}