jackwener/OpenCLI · error · CommandExecutionError
Sales Navigator messaging thread API returned malformed mess
Error message
Sales Navigator messaging thread API returned malformed message row
What it means
Thrown inside the messages.map callback of parseSalesnavThreadMessages (clis/linkedin/salesnav-thread.js:100) when any element of thread.messages is null or not an object. Each message must be an object carrying id, author, body/deliveredAt fields to build an output row. The library fails loudly on the first bad row instead of emitting rows with undefined fields, so one corrupt element aborts the whole parse.
Source
Thrown at clis/linkedin/salesnav-thread.js:100
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 || '',
type: normalizeWhitespace(message?.type || ''),
};
}).filter((row) => row.text || row.subject || row.message_id);
rows.sort((a, b) => Number(a.delivered_at || 0) - Number(b.delivered_at || 0));
return rows.map((row, index) => ({ index, ...row }));
}View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the command to see if the null row is transient; then compare which thread/message triggers it (the index before failure localizes the corrupt message).
- Filter non-object message entries before parsing: thread.messages.filter((m) => m && typeof m === 'object').
- Refresh THREAD_DECORATION from a live network capture if message fields are being decoded into wrong types.
- If a specific thread always fails (e.g. contains deleted messages), skip that thread or report it upstream so the parser can tolerate null rows.
Example fix
// before (one null row aborts everything)
const messages = parseSalesnavThreadMessages(thread);
// after (drop non-object rows first)
const cleaned = { ...thread, messages: (thread.messages || []).filter((m) => m && typeof m === 'object') };
const messages = parseSalesnavThreadMessages(cleaned); Defensive patterns
Strategy: type-guard
Validate before calling
// Sanitize message rows before parsing:
const safeThread = {
...thread,
messages: (thread.messages || []).filter((m) => m && typeof m === 'object'),
}; Type guard
function isMessageObject(m) {
return m !== null && typeof m === 'object' && !Array.isArray(m);
} Try / catch
try {
const messages = parseSalesnavThreadMessages(thread);
} catch (err) {
if (/malformed message row/.test(err.message)) {
// drop non-object rows (deleted/redacted messages serialize as null) and retry
const cleaned = { ...thread, messages: thread.messages.filter(isMessageObject) };
return parseSalesnavThreadMessages(cleaned);
}
throw err;
} Prevention
- Filter out null/non-object message entries before parsing — threads with deleted messages can contain them.
- If one specific thread always fails, isolate its raw payload; it may need special handling upstream.
- Avoid merging thread pages with spread/concat bugs that can inject undefined entries into messages.
When it happens
Trigger: The API returned an array containing null placeholders (e.g. deleted/redacted messages serialized as null); a decoration mismatch causing message entries to be decoded as strings or arrays; pagination stitching in fetchThreadWithPagination concatenating heterogeneous payloads where one page's element is not an object.
Common situations: Threads containing deleted or system-redacted messages that LinkedIn serializes as null entries; mixed-version decorations after a Sales Navigator redeploy; custom code merging thread pages before parsing and injecting undefined entries.
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Sales Navigator messaging thread API returned malformed payl
- Sales Navigator messaging thread API returned a thread witho
- Sales Navigator messaging thread API returned malformed mess
- Sales Navigator lead search API returned malformed payload
- Sales Navigator lead search API returned malformed lead row
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/4c12d9d8fb26cef0.
Report an issue: GitHub.