jackwener/OpenCLI · error · CommandExecutionError
Sales Navigator messaging thread row missing id
Error message
Sales Navigator messaging thread row missing id
What it means
This CommandExecutionError is thrown by parseSalesnavThreads when a thread row parses successfully but has no usable id (thread?.id is missing or whitespace). Thread IDs are required to build thread URLs and paginate, so rows without one are rejected rather than emitted with broken links.
Source
Thrown at clis/linkedin/salesnav-inbox.js:72
const participants = getThreadParticipants(thread);
const other = participants.find((p) => !isSelfParticipant(p)) || participants[0];
return normalizeWhitespace(other?.fullName || [other?.firstName, other?.lastName].filter(Boolean).join(' '));
}
function parseSalesnavThreads(json) {
if (!json || typeof json !== 'object' || !Array.isArray(json.elements)) {
throw new CommandExecutionError('Sales Navigator messaging threads API returned malformed payload');
}
return json.elements.map((thread) => {
if (!thread || typeof thread !== 'object') {
throw new CommandExecutionError('Sales Navigator messaging threads API returned malformed thread row');
}
const messages = Array.isArray(thread?.messages) ? thread.messages : [];
const lastMessage = messages[0] || {};
const deliveredAt = Number(lastMessage.deliveredAt || thread?.nextPageStartsAt || 0);
const threadId = normalizeWhitespace(thread?.id || '');
if (!threadId) {
throw new CommandExecutionError('Sales Navigator messaging thread row missing id');
}
return {
thread_id: threadId,
thread_url: salesnavThreadUrl(threadId),
person_name: otherParticipantName(thread),
last_message_snippet: normalizeWhitespace(lastMessage.body || lastMessage.subject || '').slice(0, 300),
last_activity_time: deliveredAt ? new Date(deliveredAt).toISOString() : '',
unread: Number(thread?.unreadMessageCount || 0) > 0,
unread_count: Number(thread?.unreadMessageCount || 0),
total_message_count: Number(thread?.totalMessageCount || messages.length || 0),
archived: Boolean(thread?.archived),
next_page_starts_at: normalizeWhitespace(thread?.nextPageStartsAt || ''),
participants: getThreadParticipants(thread).map((p) => ({
name: normalizeWhitespace(p.fullName || [p.firstName, p.lastName].filter(Boolean).join(' ')),
entity_urn: normalizeWhitespace(p.entityUrn || ''),
object_urn: normalizeWhitespace(p.objectUrn || ''),
degree: normalizeWhitespace(p.degree ?? ''),
})),View on GitHub (pinned to 49907e53dc)
Solutions
- Update the library to read the id from its new location if the schema changed
- Skip threads without ids instead of failing the whole batch (filter before mapping)
- Inspect the raw payload to find where the thread identifier now lives
- Retry with a smaller page size to avoid partially hydrated rows
Example fix
// before
if (!threadId) throw new CommandExecutionError('...missing id');
// after
if (!threadId) return null; // caller: rows.filter(Boolean)
const threadId = normalizeWhitespace(thread?.id || thread?.entity?.id || ''); Defensive patterns
Strategy: validation
Validate before calling
const usable = (json.elements || []).filter((t) => t && typeof t === 'object' && String(t.id || '').trim() !== '');
Type guard
function hasThreadId(t) {
return !!t && typeof t === 'object' && typeof t.id === 'string' && t.id.trim() !== '';
} Try / catch
try {
const rows = await fetchInboxRows(page);
} catch (e) {
if (String(e.message).includes('missing id')) {
logger.warn('Thread without id encountered; check Sales Nav schema');
return [];
}
throw e;
} Prevention
- Filter out rows without ids before parsing
- Inspect raw payloads for where the id moved after API updates
- Log thread ids as early warnings during schema drift
- Version-lock the library against tested Sales Nav responses
When it happens
Trigger: A valid thread object in json.elements lacks the id field — schema change moving the id to a nested location (e.g. entity object), or a placeholder/empty thread returned by the API.
Common situations: Sales Navigator API version updates renaming the id field; thread rows representing system/special threads without stable ids; partially hydrated responses from aggressive pagination.
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
- Sales Navigator messaging threads API returned malformed pay
- Sales Navigator messaging threads API returned malformed thr
- ${label} authentication failed (HTTP ${result.status || 'aut
- ${label} returned an unexpected response
- ${label} auth failed.
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/3d22558878e01780.
Report an issue: GitHub.