{"record":{"id":"8b4d3753561161ae","repo":"jackwener/OpenCLI","slug":"linkedin-messengermessages-api-returned-no-pages","errorCode":null,"errorMessage":"LinkedIn messengerMessages API returned no pages.","messagePattern":"LinkedIn messengerMessages API returned no pages\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/thread-snapshot.js","lineNumber":201,"sourceCode":"      throw new CommandExecutionError('LinkedIn messengerMessages discovery returned an invalid URL.');\n    }\n    let decoded = value;\n    try { decoded = decodeURIComponent(value); } catch {}\n    if (url.protocol !== 'https:'\n      || url.hostname !== LINKEDIN_DOMAIN\n      || url.pathname !== '/voyager/api/voyagerMessagingGraphQL/graphql'\n      || !/^messengerMessages\\.[a-f0-9]+$/i.test(url.searchParams.get('queryId') || '')\n      || !threadId\n      || !decoded.includes(threadId)) {\n      throw new CommandExecutionError('LinkedIn messengerMessages discovery returned an unsafe or mismatched URL.');\n    }\n  }\n  return apiUrls;\n}\n\nfunction parseThreadPages(pages) {\n  if (!Array.isArray(pages) || pages.length === 0) {\n    throw new CommandExecutionError('LinkedIn messengerMessages API returned no pages.');\n  }\n\n  const entities = new Map();\n  const apiUrls = [];\n  for (const page of pages) {\n    if (!page || typeof page !== 'object' || Array.isArray(page) || typeof page.url !== 'string') {\n      throw new CommandExecutionError('LinkedIn messengerMessages API returned a malformed page wrapper.');\n    }\n    const normalized = page.json;\n    if (!normalized || typeof normalized !== 'object' || Array.isArray(normalized)) {\n      throw new CommandExecutionError('LinkedIn messengerMessages API returned a malformed normalized payload.');\n    }\n    if (Array.isArray(normalized.errors) && normalized.errors.length > 0) {\n      throw new CommandExecutionError('LinkedIn messengerMessages GraphQL returned errors.');\n    }\n    if (!Array.isArray(normalized.included)) {\n      throw new CommandExecutionError('LinkedIn messengerMessages payload is missing the included entity array.');\n    }","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/thread-snapshot.js#L183-L219","documentation":"Thrown by parseThreadPages when the in-page fetch script returns no pages to parse. The discovery/validation stage produced URLs, but the replay fetch loop yielded an empty or missing pages array, so there is no payload to extract messages from. It separates 'nothing was fetched' from 'fetched payload was malformed'.","triggerScenarios":"buildFetchThreadPagesScript resolves with an object lacking a non-empty pages array — e.g. the script returned its top-level { authRequired } or { error } branch result instead of { pages }, or apiUrls was reduced to zero entries between validation and fetch.","commonSituations":"Session cookie expired mid-run so the fetch script bailed with 401/403 and returned an error object; a network failure produced { error } instead of { pages }; the caller passed the wrong result object into parseThreadPages after an unexpected browser-navigation reset.","solutions":["Check the returned object for authRequired or error fields first and surface those (re-authenticate or retry) instead of calling parseThreadPages.","Re-run the command after confirming the LinkedIn session is alive (page not on a login/checkpoint URL).","Ensure the caller only invokes parseThreadPages with the { pages } result of a successful fetch script run."],"exampleFix":"// before\nparseThreadPages(result);\n// after\nif (result.authRequired) throw new AuthRequiredError();\nif (result.error) throw new CommandExecutionError(result.error);\nparseThreadPages(result.pages);","handlingStrategy":"try-catch","validationCode":"const result = await runFetchScript();\nif (!result || !Array.isArray(result.pages) || result.pages.length === 0) {\n  throw new Error('Fetch returned no pages: ' + (result && (result.error || result.authRequired)));\n}","typeGuard":"function hasPages(r) {\n  return Boolean(r) && typeof r === 'object'\n    && Array.isArray(r.pages) && r.pages.length > 0;\n}","tryCatchPattern":"try {\n  const snapshot = await cli.linkedin.threadSnapshot({ url: threadUrl });\n} catch (err) {\n  if (err.message.includes('returned no pages')) {\n    // re-authenticate if the session expired, then retry once\n  } else throw err;\n}","preventionTips":["Confirm the LinkedIn session is live (not on a login/checkpoint page) before running.","Handle authRequired/error fields from the fetch result before attempting to parse.","Retry transient network failures with a short backoff."],"tags":["linkedin","empty-response","scraping"],"backgroundTag":"empty-response-body","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}