jackwener/OpenCLI · error · CommandExecutionError
LinkedIn messengerMessages payload contains a message with a
Error message
LinkedIn messengerMessages payload contains a message with an unresolved sender.
What it means
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'.
Source
Thrown at clis/linkedin/thread-snapshot.js:279
throw new CommandExecutionError('LinkedIn messengerMessages payload is missing the counterparty participant.');
}
const byMessageId = new Map();
for (const entity of entities.values()) {
if (entity.$type !== 'com.linkedin.messenger.Message') continue;
const messageId = normalizeWhitespace(entity.entityUrn || entity.backendUrn || entity.originToken);
if (!messageId) {
throw new CommandExecutionError('LinkedIn messengerMessages payload contains a message without an id.');
}
const deliveredAt = Number(entity.deliveredAt);
if (!Number.isFinite(deliveredAt) || deliveredAt <= 0) {
throw new CommandExecutionError('LinkedIn messengerMessages payload contains a message without a valid timestamp.');
}
const senderUrn = normalizeWhitespace(entity['*sender'] || entity['*actor']);
const sender = senderUrn ? entities.get(senderUrn) : null;
const speaker = participantName(sender);
if (!speaker) {
throw new CommandExecutionError('LinkedIn messengerMessages payload contains a message with an unresolved sender.');
}
byMessageId.set(messageId, {
messageUrn: messageId,
speaker,
text: messageText(entity),
deliveredAt,
});
}
const messages = Array.from(byMessageId.values())
.sort((left, right) => left.deliveredAt - right.deliveredAt || left.messageUrn.localeCompare(right.messageUrn))
.map((message, index) => ({ index, ...message }));
if (messages.length === 0) {
throw new EmptyResultError('linkedin thread-snapshot', 'No messages were found in the LinkedIn thread.');
}
return { recipientNames, messages };
}
View on GitHub (pinned to 49907e53dc)
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
Example fix
// before const senderUrn = normalizeWhitespace(entity['*sender'] || entity['*actor']); // after: include new schema back-reference const senderUrn = normalizeWhitespace(entity['*sender'] || entity['*actor'] || entity['*messagingParticipant']);
Defensive patterns
Strategy: validation
Validate before calling
function senderResolves(payload) {
const byUrn = new Map(payload.included.filter(Boolean).filter(e => e.entityUrn).map(e => [e.entityUrn, e]));
return payload.included.filter(e => e?.$type === 'com.linkedin.messenger.Message').every(m => {
const urn = m['*sender'] || m['*actor'];
return urn && byUrn.get(urn);
});
}
if (!pages.every(p => senderResolves(p.json))) throw new Error('Unresolved senders in payload'); Type guard
const isResolvableMessage = (m, byUrn) => {
const urn = m?.['*sender'] || m?.['*actor'];
return typeof urn === 'string' && byUrn.get(urn)?.$type === 'com.linkedin.messenger.MessagingParticipant';
}; Try / catch
try {
const snap = await run('linkedin thread-snapshot', { 'thread-url': url });
} catch (err) {
if (String(err.message).includes('unresolved sender')) {
// re-capture to include participant entities, or handle restricted profiles
} else throw err;
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- linkedin.com: LinkedIn li_at cookie missing
- linkedin.com: ${result.detail}
- HTTP ${result.httpStatus} from /voyager/api/me
- LinkedIn Learning whoami failed: ${result.detail}
- Unexpected LinkedIn Learning probe: ${JSON.stringify(result)
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/ffca8620a61a900b.
Report an issue: GitHub.