jackwener/OpenCLI · error · CommandExecutionError

LinkedIn messengerMessages payload is missing a message coll

Error message

LinkedIn messengerMessages payload is missing a message collection.

What it means

Thrown by parseThreadPages when no key under normalized.data.data matches the messengerMessages container shape — an object with a '*elements' (or 'elements') array. This container holds the URNs of the messages in the thread; without it the payload, though otherwise valid, contains no message collection to snapshot.

Source

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

    if (Array.isArray(normalized.errors) && normalized.errors.length > 0) {
      throw new CommandExecutionError('LinkedIn messengerMessages GraphQL returned errors.');
    }
    if (!Array.isArray(normalized.included)) {
      throw new CommandExecutionError('LinkedIn messengerMessages payload is missing the included entity array.');
    }
    const data = normalized.data?.data;
    if (!data || typeof data !== 'object' || Array.isArray(data)) {
      throw new CommandExecutionError('LinkedIn messengerMessages payload is missing normalized data.');
    }
    const container = Object.entries(data).find(([key, value]) => (
      /^messengerMessages/i.test(key)
      && value
      && typeof value === 'object'
      && !Array.isArray(value)
      && (Array.isArray(value['*elements']) || Array.isArray(value.elements))
    ));
    if (!container) {
      throw new CommandExecutionError('LinkedIn messengerMessages payload is missing a message collection.');
    }
    for (const entity of normalized.included) {
      if (!entity || typeof entity !== 'object' || Array.isArray(entity)) {
        throw new CommandExecutionError('LinkedIn messengerMessages payload contains a malformed included entity.');
      }
      if (entity.entityUrn) {
        const existing = entities.get(entity.entityUrn);
        if (!existing || Object.keys(entity).length > Object.keys(existing).length) {
          entities.set(entity.entityUrn, entity);
        }
      }
    }
    apiUrls.push(page.url);
  }

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

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Confirm every validated apiUrl is a messengerMessages query (queryId regex) and not another voyager operation.
  2. Reload the thread and rerun so fresh requests with the correct operation are captured.
  3. Inspect the data.data keys in devtools; if LinkedIn renamed the container, update the /^messengerMessages/i key test and the '*elements'/'elements' shape check.
  4. If the thread genuinely has no messages, treat empty threads as a supported case rather than a parse failure.

Example fix

// before: exact key assumption breaks on rename
const container = data.messengerMessages;
// after: shape-based lookup (as the library does)
const container = Object.entries(data).find(([key, value]) =>
  /^messengerMessages/i.test(key)
  && value && typeof value === 'object' && !Array.isArray(value)
  && (Array.isArray(value['*elements']) || Array.isArray(value.elements))
);
Defensive patterns

Strategy: validation

Validate before calling

const data = json?.data?.data;
const hasContainer = data && Object.entries(data).some(([k, v]) =>
  /^messengerMessages/i.test(k) && v && typeof v === 'object' && !Array.isArray(v)
  && (Array.isArray(v['*elements']) || Array.isArray(v.elements)));
if (!hasContainer) throw new Error('No messengerMessages collection in payload');

Type guard

function isMessageContainer(v) {
  return Boolean(v) && typeof v === 'object' && !Array.isArray(v)
    && (Array.isArray(v['*elements']) || Array.isArray(v.elements));
}

Try / catch

try {
  const snapshot = await cli.linkedin.threadSnapshot({ url: threadUrl });
} catch (err) {
  if (err.message.includes('missing a message collection')) {
    // confirm the captured URL is a messengerMessages operation; reload and retry
  } else throw err;
}

Prevention

When it happens

Trigger: Object.entries(data) finds no key where /^messengerMessages/i matches the key AND the value is a non-array object AND value['*elements'] or value.elements is an array — e.g. data.data exists but holds a different operation's result or an empty result object.

Common situations: The replayed URL was a different GraphQL operation (not messengerMessages) that slipped through discovery; LinkedIn renamed the result key after an API update; the server returned an operation object without elements for an empty/deleted thread.

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/83be7bce2dbf63b7. Report an issue: GitHub.