{"record":{"id":"6456efcc53116385","repo":"jackwener/OpenCLI","slug":"linkedin-messengermessages-api-returned-a-malforme","errorCode":null,"errorMessage":"LinkedIn messengerMessages API returned a malformed page wrapper.","messagePattern":"LinkedIn messengerMessages API returned a malformed page wrapper\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/thread-snapshot.js","lineNumber":208,"sourceCode":"      || !/^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    }\n    const data = normalized.data?.data;\n    if (!data || typeof data !== 'object' || Array.isArray(data)) {\n      throw new CommandExecutionError('LinkedIn messengerMessages payload is missing normalized data.');\n    }\n    const container = Object.entries(data).find(([key, value]) => (\n      /^messengerMessages/i.test(key)\n      && value","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/thread-snapshot.js#L190-L226","documentation":"Thrown by parseThreadPages when an individual page entry is not a plain object with a string url property. Each page must be the { url, json } wrapper the fetch script builds; anything else means the caller passed data of an unexpected shape or the fetch script's contract changed.","triggerScenarios":"A pages element is null/undefined, an array, a primitive, or an object whose .url is not a string — e.g. pages was constructed manually, or the fetch script was updated to return a different wrapper shape.","commonSituations":"Developer reused parseThreadPages with raw JSON responses instead of { url, json } wrappers; a forked/modified fetch script renamed or dropped the url field; caching layers serialized/deserialized pages into arrays or null entries.","solutions":["Pass the untouched { pages } array returned by buildFetchThreadPagesScript into parseThreadPages — do not unwrap or rebuild the wrappers.","Validate each page ({ url: string, json: object }) in the caller before parsing.","If the fetch script was customized, restore the { url, json } contract or update parseThreadPages accordingly."],"exampleFix":"// before: unwrapping json and losing the wrapper\nconst pages = responses.map((r) => r.json);\nparseThreadPages(pages);\n// after: keep the wrapper shape\nconst pages = responses.map((r) => ({ url: r.url, json: r.json }));\nparseThreadPages(pages);","handlingStrategy":"type-guard","validationCode":"if (!pages.every((p) => p && typeof p === 'object' && !Array.isArray(p) && typeof p.url === 'string')) {\n  throw new Error('Each page must be a { url: string, json: object } wrapper');\n}","typeGuard":"function isPageWrapper(p) {\n  return Boolean(p) && typeof p === 'object' && !Array.isArray(p)\n    && typeof p.url === 'string'\n    && Boolean(p.json) && typeof p.json === 'object' && !Array.isArray(p.json);\n}","tryCatchPattern":"try {\n  const snapshot = await cli.linkedin.threadSnapshot({ url: threadUrl });\n} catch (err) {\n  if (err.message.includes('malformed page wrapper')) {\n    // stop passing unwrapped/reshaped fetch results; use the library's pipeline end to end\n  } else throw err;\n}","preventionTips":["Feed parseThreadPages only the raw { pages } output of the fetch script.","Do not unwrap { url, json } wrappers into bare JSON before parsing.","Type-check intermediate results when adapting the pipeline in custom scripts."],"tags":["linkedin","schema-validation","scraping"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}