jackwener/OpenCLI · error · CommandExecutionError

Sales Navigator messaging thread API returned partial…

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.

Solutions

  1. Retry the command; transient truncation often resolves on a second run.
  2. Raise --limit so have is no longer below the limit used in the check (the error only fires when have < limit).
  3. 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.
  4. 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

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


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

Appendix: 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)