jackwener/OpenCLI · error · CommandExecutionError

Sales Navigator messaging thread API returned malformed mess

Error message

Sales Navigator messaging thread API returned malformed messages

What it means

Thrown by parseSalesnavThreadMessages (clis/linkedin/salesnav-thread.js:94) when thread.messages is present but not an array. The parser requires an array to map each message into an output row. This indicates the API payload deviates from the expected decoration shape, typically because the response came from a different endpoint/version or was partially decoded.

Source

Thrown at clis/linkedin/salesnav-thread.js:94

  const participants = Array.isArray(thread?.participants) ? thread.participants : Object.keys(resolution);
  const byUrn = new Map();
  for (const urn of participants) {
    const profile = resolution[urn] || { entityUrn: urn };
    byUrn.set(urn, profile);
  }
  return byUrn;
}

function parseSalesnavThreadMessages(thread) {
  if (!thread || typeof thread !== 'object') {
    throw new CommandExecutionError('Sales Navigator messaging thread API returned malformed payload');
  }
  const threadId = normalizeWhitespace(thread?.id || '');
  if (!threadId) {
    throw new CommandExecutionError('Sales Navigator messaging thread API returned a thread without id');
  }
  if (!Array.isArray(thread?.messages)) {
    throw new CommandExecutionError('Sales Navigator messaging thread API returned malformed messages');
  }
  const byUrn = participantIndex(thread);
  const messages = thread.messages;
  const rows = messages.map((message) => {
    if (!message || typeof message !== 'object') {
      throw new CommandExecutionError('Sales Navigator messaging thread API returned malformed message row');
    }
    const deliveredAt = Number(message?.deliveredAt || 0);
    const senderProfile = byUrn.get(message?.author);
    return {
      message_id: normalizeWhitespace(message?.id || ''),
      thread_id: threadId,
      sender: participantName(senderProfile) || normalizeWhitespace(message?.author || ''),
      sender_urn: normalizeWhitespace(message?.author || ''),
      text: normalizeWhitespace(message?.body || message?.systemMessageContent || ''),
      subject: normalizeWhitespace(message?.subject || ''),
      timestamp: deliveredAt ? new Date(deliveredAt).toISOString() : '',
      delivered_at: deliveredAt || '',

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run the command; if it recurs, the payload shape has changed rather than being transient.
  2. Inspect the raw response (log Object.keys(thread) and typeof thread.messages) to find where messages now live under the current decoration.
  3. Update THREAD_DECORATION from a live /sales-api/salesApiThreads network capture so the decoder restores the messages array.
  4. Confirm you parsed the thread-detail endpoint response; inbox-list rows keep messages elsewhere and will fail this check.

Example fix

// before
const rows = parseSalesnavThreadMessages(thread);
// after (tolerate missing messages for empty threads)
const safeThread = { ...thread, messages: Array.isArray(thread.messages) ? thread.messages : [] };
const rows = parseSalesnavThreadMessages(safeThread);
Defensive patterns

Strategy: type-guard

Validate before calling

// Coerce/guard messages before parsing:
const safeThread = { ...thread, messages: Array.isArray(thread.messages) ? thread.messages : [] };
// note: an empty array still means 'no messages', which the caller should expect

Type guard

function hasMessagesArray(t) {
  return t !== null && typeof t === 'object' && Array.isArray(t.messages);
}

Try / catch

try {
  const messages = parseSalesnavThreadMessages(thread);
} catch (err) {
  if (/malformed messages/.test(err.message)) {
    console.error('messages is not an array — check decoration version and raw payload keys:', Object.keys(thread || {}));
    throw err;
  }
  throw err;
}

Prevention

When it happens

Trigger: The decoration version mismatch relocates messages into a nested object or renames the field (e.g. messagesResolutionResults); fetchSalesnavJson returned an error/HTML-parsed object where messages is a string; caller passes a thread summary object that omits messages entirely (undefined fails the Array.isArray check).

Common situations: LinkedIn Sales Navigator redeploys changing the message container; calling the parser with a thread object built from the wrong endpoint; messageCount=0 edge responses where the field is omitted rather than returned as [].

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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