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

  1. Re-run the snapshot to capture a complete payload including all referenced participant entities
  2. Update the library — check whether the sender back-reference field was renamed and extend the '*sender'/'*actor' fallback chain
  3. Inspect the message entity's keys for new sender fields and the entities map for the referenced URN
  4. 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

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


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/ffca8620a61a900b. Report an issue: GitHub.