{"record":{"id":"0a7b4c5aa3395aac","repo":"jackwener/OpenCLI","slug":"linkedin-messengermessages-payload-is-missing-norm","errorCode":null,"errorMessage":"LinkedIn messengerMessages payload is missing normalized data.","messagePattern":"LinkedIn messengerMessages payload is missing normalized data\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/thread-snapshot.js","lineNumber":222,"sourceCode":"  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\n      && typeof value === 'object'\n      && !Array.isArray(value)\n      && (Array.isArray(value['*elements']) || Array.isArray(value.elements))\n    ));\n    if (!container) {\n      throw new CommandExecutionError('LinkedIn messengerMessages payload is missing a message collection.');\n    }\n    for (const entity of normalized.included) {\n      if (!entity || typeof entity !== 'object' || Array.isArray(entity)) {\n        throw new CommandExecutionError('LinkedIn messengerMessages payload contains a malformed included entity.');\n      }\n      if (entity.entityUrn) {\n        const existing = entities.get(entity.entityUrn);\n        if (!existing || Object.keys(entity).length > Object.keys(existing).length) {","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/thread-snapshot.js#L204-L240","documentation":"Thrown by parseThreadPages when normalized.data?.data is missing or not a plain object. In LinkedIn's normalized payloads the GraphQL result lives at json.data.data; without it there is no messengerMessages container to locate, so the library cannot extract the element URNs for the thread.","triggerScenarios":"normalized.data is undefined, normalized.data.data is null/an array/a primitive — typically an operation-level GraphQL null (errors suppressed), a partially failed response, or an envelope with extra nesting from a changed endpoint.","commonSituations":"GraphQL returned { data: { messengerMessages: null } }-style partial failures without an errors array; the replayed queryId resolved to an operation whose result shape differs; a middle/proxy re-wrapped the JSON with an extra layer.","solutions":["Log normalized.data to inspect the actual nesting and confirm the expected data.data envelope.","Reload and rerun to capture fresh request URLs in case the stored one returns a partial/failed operation.","Check the GraphQL errors path too — data.data can be null when the operation failed silently.","If LinkedIn added envelope nesting, adjust the data?.data access path in parseThreadPages."],"exampleFix":"// before: blind access\nconst data = json.data.data;\n// after: safe access with diagnostics\nconst data = json.data?.data;\nif (!data || typeof data !== 'object' || Array.isArray(data)) {\n  throw new CommandExecutionError('missing normalized data; keys=' + Object.keys(json.data || {}).join(','));\n}","handlingStrategy":"type-guard","validationCode":"const data = json?.data?.data;\nif (!data || typeof data !== 'object' || Array.isArray(data)) {\n  throw new Error('Normalized payload missing data.data');\n}","typeGuard":"function hasGraphQLData(json) {\n  const d = json?.data?.data;\n  return Boolean(d) && typeof d === 'object' && !Array.isArray(d);\n}","tryCatchPattern":"try {\n  const snapshot = await cli.linkedin.threadSnapshot({ url: threadUrl });\n} catch (err) {\n  if (err.message.includes('missing normalized data')) {\n    // inspect json.data for null operation results; reload and retry\n  } else throw err;\n}","preventionTips":["Check for GraphQL errors before reading data.data — null results often accompany them.","Capture fresh request URLs via page reload rather than reusing stale ones.","Verify the envelope nesting if a proxy re-wraps responses."],"tags":["linkedin","graphql","schema-validation","scraping"],"backgroundTag":"missing-required-field","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}