jackwener/OpenCLI · error · CommandExecutionError

LinkedIn messengerMessages payload is missing normalized dat

Error message

LinkedIn messengerMessages payload is missing normalized data.

What it means

Thrown by parseThreadPages when normalized.data?.data is missing or not a plain object. In LinkedIn's normalized payloads the GraphQL result lives at json.data.data; without it there is no messengerMessages container to locate, so the library cannot extract the element URNs for the thread.

Source

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

  const entities = new Map();
  const apiUrls = [];
  for (const page of pages) {
    if (!page || typeof page !== 'object' || Array.isArray(page) || typeof page.url !== 'string') {
      throw new CommandExecutionError('LinkedIn messengerMessages API returned a malformed page wrapper.');
    }
    const normalized = page.json;
    if (!normalized || typeof normalized !== 'object' || Array.isArray(normalized)) {
      throw new CommandExecutionError('LinkedIn messengerMessages API returned a malformed normalized payload.');
    }
    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) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log normalized.data to inspect the actual nesting and confirm the expected data.data envelope.
  2. Reload and rerun to capture fresh request URLs in case the stored one returns a partial/failed operation.
  3. Check the GraphQL errors path too — data.data can be null when the operation failed silently.
  4. If LinkedIn added envelope nesting, adjust the data?.data access path in parseThreadPages.

Example fix

// before: blind access
const data = json.data.data;
// after: safe access with diagnostics
const data = json.data?.data;
if (!data || typeof data !== 'object' || Array.isArray(data)) {
  throw new CommandExecutionError('missing normalized data; keys=' + Object.keys(json.data || {}).join(','));
}
Defensive patterns

Strategy: type-guard

Validate before calling

const data = json?.data?.data;
if (!data || typeof data !== 'object' || Array.isArray(data)) {
  throw new Error('Normalized payload missing data.data');
}

Type guard

function hasGraphQLData(json) {
  const d = json?.data?.data;
  return Boolean(d) && typeof d === 'object' && !Array.isArray(d);
}

Try / catch

try {
  const snapshot = await cli.linkedin.threadSnapshot({ url: threadUrl });
} catch (err) {
  if (err.message.includes('missing normalized data')) {
    // inspect json.data for null operation results; reload and retry
  } else throw err;
}

Prevention

When it happens

Trigger: normalized.data is undefined, normalized.data.data is null/an array/a primitive — typically an operation-level GraphQL null (errors suppressed), a partially failed response, or an envelope with extra nesting from a changed endpoint.

Common situations: GraphQL returned { data: { messengerMessages: null } }-style partial failures without an errors array; the replayed queryId resolved to an operation whose result shape differs; a middle/proxy re-wrapped the JSON with an extra layer.

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/0a7b4c5aa3395aac. Report an issue: GitHub.