{"record":{"id":"ffca8620a61a900b","repo":"jackwener/OpenCLI","slug":"linkedin-messengermessages-payload-contains-a-mess-ffca86","errorCode":null,"errorMessage":"LinkedIn messengerMessages payload contains a message with an unresolved sender.","messagePattern":"LinkedIn messengerMessages payload contains a message with an unresolved sender\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/thread-snapshot.js","lineNumber":279,"sourceCode":"    throw new CommandExecutionError('LinkedIn messengerMessages payload is missing the counterparty participant.');\n  }\n\n  const byMessageId = new Map();\n  for (const entity of entities.values()) {\n    if (entity.$type !== 'com.linkedin.messenger.Message') continue;\n    const messageId = normalizeWhitespace(entity.entityUrn || entity.backendUrn || entity.originToken);\n    if (!messageId) {\n      throw new CommandExecutionError('LinkedIn messengerMessages payload contains a message without an id.');\n    }\n    const deliveredAt = Number(entity.deliveredAt);\n    if (!Number.isFinite(deliveredAt) || deliveredAt <= 0) {\n      throw new CommandExecutionError('LinkedIn messengerMessages payload contains a message without a valid timestamp.');\n    }\n    const senderUrn = normalizeWhitespace(entity['*sender'] || entity['*actor']);\n    const sender = senderUrn ? entities.get(senderUrn) : null;\n    const speaker = participantName(sender);\n    if (!speaker) {\n      throw new CommandExecutionError('LinkedIn messengerMessages payload contains a message with an unresolved sender.');\n    }\n    byMessageId.set(messageId, {\n      messageUrn: messageId,\n      speaker,\n      text: messageText(entity),\n      deliveredAt,\n    });\n  }\n\n  const messages = Array.from(byMessageId.values())\n    .sort((left, right) => left.deliveredAt - right.deliveredAt || left.messageUrn.localeCompare(right.messageUrn))\n    .map((message, index) => ({ index, ...message }));\n  if (messages.length === 0) {\n    throw new EmptyResultError('linkedin thread-snapshot', 'No messages were found in the LinkedIn thread.');\n  }\n  return { recipientNames, messages };\n}\n","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/thread-snapshot.js#L261-L297","documentation":"Each Message carries a sender reference (*sender or *actor URN) that must resolve to a known MessagingParticipant entity with a derivable display name. The parser throws when the sender URN is missing or no matching participant entity with a name exists in the collected entities map, since every snapshot message needs a 'speaker'.","triggerScenarios":"A Message entity has neither '*sender' nor '*actor'; the sender URN points to an entity absent from `included`; or the participant entity exists but participantName() can't extract a name (privacy-restricted profile).","commonSituations":"Truncated capture that dropped the participant entity referenced by the message; LinkedIn restricting profile data for other members; schema change renaming the sender back-reference field; fixtures missing participant entities.","solutions":["Re-run the snapshot to capture a complete payload including all referenced participant entities","Update the library — check whether the sender back-reference field was renamed and extend the '*sender'/'*actor' fallback chain","Inspect the message entity's keys for new sender fields and the entities map for the referenced URN","If the counterparty's profile is restricted, test with a thread whose participants' names are visible to your session"],"exampleFix":"// before\nconst senderUrn = normalizeWhitespace(entity['*sender'] || entity['*actor']);\n// after: include new schema back-reference\nconst senderUrn = normalizeWhitespace(entity['*sender'] || entity['*actor'] || entity['*messagingParticipant']);","handlingStrategy":"validation","validationCode":"function senderResolves(payload) {\n  const byUrn = new Map(payload.included.filter(Boolean).filter(e => e.entityUrn).map(e => [e.entityUrn, e]));\n  return payload.included.filter(e => e?.$type === 'com.linkedin.messenger.Message').every(m => {\n    const urn = m['*sender'] || m['*actor'];\n    return urn && byUrn.get(urn);\n  });\n}\nif (!pages.every(p => senderResolves(p.json))) throw new Error('Unresolved senders in payload');","typeGuard":"const isResolvableMessage = (m, byUrn) => {\n  const urn = m?.['*sender'] || m?.['*actor'];\n  return typeof urn === 'string' && byUrn.get(urn)?.$type === 'com.linkedin.messenger.MessagingParticipant';\n};","tryCatchPattern":"try {\n  const snap = await run('linkedin thread-snapshot', { 'thread-url': url });\n} catch (err) {\n  if (String(err.message).includes('unresolved sender')) {\n    // re-capture to include participant entities, or handle restricted profiles\n  } else throw err;\n}","preventionTips":["Capture all pages so referenced participant entities are included","Keep the '*sender'/'*actor' fallback chain current with schema changes","Test against threads with visible participant names for your session"],"tags":["linkedin","unresolved-reference","sender-missing"],"backgroundTag":"unresolved-entity-reference","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}