jackwener/OpenCLI · error · CommandExecutionError

LinkedIn messengerMessages payload is missing the counterpar

Error message

LinkedIn messengerMessages payload is missing the counterparty participant.

What it means

parseThreadPages filters MessagingParticipant entities to those whose hostIdentityUrn differs from the owner URN, then derives display names. It throws when no counterparty (non-owner) participant yields a name, meaning the payload has no usable other-side participant entity — so the snapshot would have no 'recipient'.

Source

Thrown at clis/linkedin/thread-snapshot.js:261

      }
    }
    apiUrls.push(page.url);
  }

  const ownerUrn = ownerUrnFromApiUrls(apiUrls);
  if (!ownerUrn) {
    throw new CommandExecutionError('LinkedIn messengerMessages URL is missing the conversation owner identity.');
  }

  const participants = Array.from(entities.values()).filter(
    (entity) => entity.$type === 'com.linkedin.messenger.MessagingParticipant',
  );
  const recipientNames = Array.from(new Set(participants
    .filter((participant) => participant.hostIdentityUrn !== ownerUrn)
    .map(participantName)
    .filter(Boolean)));
  if (recipientNames.length === 0) {
    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.');

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run the snapshot to capture a complete payload including participant entities
  2. Update the library — participantName may need to handle new name field layouts for MessagingParticipant
  3. Test with a normal thread with an active counterparty to confirm the tool works; threads to self/deactivated accounts are unsupported
  4. If capturing manually, include all pages so participant entities in later pages aren't lost

Example fix

// before: participant entity lacking name fields
{ "$type": "com.linkedin.messenger.MessagingParticipant", "hostIdentityUrn": "urn:li:person:abc" }
// after: complete capture including the linked miniProfile name fields
{ "$type": "com.linkedin.messenger.MessagingParticipant", "hostIdentityUrn": "urn:li:person:abc", "name": { "firstName": "Jane", "lastName": "Doe" } }
Defensive patterns

Strategy: validation

Validate before calling

function hasCounterparty(payload, ownerUrn) {
  return payload.included.some(e => e?.$type === 'com.linkedin.messenger.MessagingParticipant'
    && e.hostIdentityUrn !== ownerUrn);
}
if (!pages.every(p => hasCounterparty(p.json, myOwnerUrn))) throw new Error('No counterparty participant captured');

Type guard

const isParticipant = (e) => !!e && typeof e === 'object' && e.$type === 'com.linkedin.messenger.MessagingParticipant' && typeof e.hostIdentityUrn === 'string';

Try / catch

try {
  const snap = await run('linkedin thread-snapshot', { 'thread-url': url });
} catch (err) {
  if (String(err.message).includes('missing the counterparty participant')) {
    // handle self-threads or restricted profiles gracefully
  } else throw err;
}

Prevention

When it happens

Trigger: All MessagingParticipant entities match the owner URN, participantName() returns empty for the counterparty entities, or the counterparty participant entity is absent from `included` (e.g. restricted/deactivated profile or incomplete included array).

Common situations: Messaging a restricted or deleted account; LinkedIn omitting participant entities for privacy; a truncated page capture that missed participant entities; self-directed threads (message to self) that genuinely have no counterparty.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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