jackwener/OpenCLI · error · CommandExecutionError
Sales Navigator messaging thread API returned partial histor
Error message
Sales Navigator messaging thread API returned partial history (${have}/${total}) What it means
fetchThreadWithPagination keeps requesting older message pages until the requested count reaches the limit. After fetching it compares LinkedIn's reported totalMessageCount with the number of messages actually collected; if fewer were returned than both the total and the requested limit, it throws CommandExecutionError about partial history. The library refuses to silently return an incomplete conversation.
Source
Thrown at clis/linkedin/salesnav-thread.js:165
async function fetchThreadWithPagination(page, csrf, threadId, limit = DEFAULT_MESSAGE_LIMIT) {
let requested = THREAD_PAGE_SIZE;
if (limit < requested) requested = limit;
let thread = null;
for (let attempts = 0; attempts < 30; attempts += 1) {
thread = await fetchSalesnavJson(page, csrf, threadApiUrl(threadId, requested), 'Sales Navigator messaging thread API');
const total = Number(thread?.totalMessageCount || 0);
const have = Array.isArray(thread?.messages) ? thread.messages.length : 0;
if (have >= limit || (total && have >= total) || requested >= limit) break;
let nextRequested = requested + THREAD_PAGE_SIZE;
if (total && total > nextRequested) nextRequested = total;
if (nextRequested > limit) nextRequested = limit;
requested = nextRequested;
}
const total = Number(thread?.totalMessageCount || 0);
const have = Array.isArray(thread?.messages) ? thread.messages.length : 0;
if (total && have < total && have < limit) {
throw new CommandExecutionError(`Sales Navigator messaging thread API returned partial history (${have}/${total})`);
}
return thread;
}
cli({
site: 'linkedin',
name: 'salesnav-thread',
access: 'read',
description: 'Return full Sales Navigator message history for a thread id, Sales Navigator inbox URL, lead URL, recipient urn, or exact recipient name',
domain: LINKEDIN_DOMAIN,
strategy: Strategy.UI,
browser: true,
args: [
{ name: 'thread-or-recipient', type: 'string', required: true, positional: true, help: 'Sales Navigator inbox URL/thread id, Sales Navigator lead URL, recipient urn, or exact participant name' },
{ name: 'limit', type: 'number', default: DEFAULT_MESSAGE_LIMIT, help: 'Maximum messages to return (1-500)' },
{ name: 'max-pages', type: 'number', default: 30, help: 'Maximum inbox pages to scan when resolving a recipient' },
],
columns: ['index', 'thread_id', 'thread_url', 'sender', 'text', 'timestamp', 'subject', 'message_id', 'sender_urn', 'delivered_at', 'type', 'total_message_count'],View on GitHub (pinned to 49907e53dc)
Solutions
- Retry the command; transient truncation often resolves on a second run.
- Raise --limit so have is no longer below the limit used in the check (the error only fires when have < limit).
- Inspect the thread in Sales Navigator to confirm messages were deleted/hidden; if so, accept the partial history by handling the error and using what was fetched on a later attempt with a smaller limit.
- Report/pin the LinkedIn API version if the thread API recently changed behavior.
Example fix
// before
thread = await fetchThreadWithPagination(page, csrf, threadId, 500) // partial -> throws
// after
try {
thread = await fetchThreadWithPagination(page, csrf, threadId, 500)
} catch (e) {
if (/partial history/.test(e.message)) {
thread = await fetchThreadWithPagination(page, csrf, threadId, 50) // smaller limit avoids have<limit trigger
} else throw e
} Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
null
Try / catch
try { thread = await thread() } catch (e) { if (/partial history \(\d+\/\d+\)/.test(e.message)) { await sleep(1000); thread = await thread(); /* or accept partial with lower limit */ } else throw e; } Prevention
- Retry transient truncations before treating them as permanent.
- Compare fetched count vs totalMessageCount yourself and log mismatches.
- Keep --limit realistic; the error only fires when have < limit.
- Watch LinkedIn messaging API changelog for pagination regressions.
When it happens
Trigger: LinkedIn's messaging thread API stops returning further pages before totalMessageCount is reached (e.g. an empty or truncated next-page cursor, deleted/hidden messages, or an API response that reports a larger total than it will actually serve), while have < the requested limit.
Common situations: Threads where LinkedIn has hidden or deleted some older messages so the real retrievable count is below totalMessageCount; transient API flakiness returning a final page early; very long threads where pagination ends prematurely after a LinkedIn messaging API change.
Related errors
- Sales Navigator messaging threads API returned malformed pay
- Sales Navigator messaging threads API returned malformed thr
- Sales Navigator messaging thread row missing id
- ${label} authentication failed (HTTP ${result.status || 'aut
- ${label} returned an unexpected response
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/9c8fde00151d17a4.
Report an issue: GitHub.