jackwener/OpenCLI · error · EmptyResultError

No Sales Navigator thread matched ${input}

Error message

No Sales Navigator thread matched ${input}

What it means

When the input is non-empty but not a literal thread id, resolveThreadId paginates up to 500 inbox rows (maxPages pages) and looks for a row matching the parsed recipient/lead/name. If no inbox row matches, it throws EmptyResultError('linkedin salesnav-thread', ...). It signals 'input is valid, but the matcher found nothing in the accessible inbox'.

Source

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

    return (row.participants || []).some((p) => normalizeWhitespace(p.entity_urn) === criterion);
  }
  if (kind === 'name') {
    const needle = normalizeWhitespace(criterion).toLowerCase();
    if (!needle) return false;
    if (normalizeWhitespace(row.person_name).toLowerCase() === needle) return true;
    return (row.participants || []).some((p) => normalizeWhitespace(p.name).toLowerCase() === needle);
  }
  return false;
}

async function resolveThreadId(page, input, { maxPages = 30 } = {}) {
  const parsed = parseThreadInput(input);
  if (parsed[0] === 'empty') throw new ArgumentError('thread or recipient is required');
  if (parsed[0] === 'thread_id') return parsed[1];
  const inboxRows = await fetchInboxRows(page, { limit: 500, maxPages });
  const match = inboxRows.find((row) => threadMatchesInput(row, parsed));
  if (!match) {
    throw new EmptyResultError('linkedin salesnav-thread', `No Sales Navigator thread matched ${input}`);
  }
  return match.thread_id;
}

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;
  }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass the numeric Sales Navigator thread id (from the inbox URL) directly instead of a name so resolution is skipped.
  2. Verify the exact participant name matches Sales Navigator (copy/paste it).
  3. Increase --max-pages so more inbox pages are scanned before giving up.
  4. Confirm you are signed into the LinkedIn account that actually owns the conversation.
  5. Open the thread in Sales Navigator and pass its inbox URL.

Example fix

// before
node cli.js linkedin salesnav-thread "Jane Doe"        # fuzzy name miss
// after
node cli.js linkedin salesnav-thread "Jane Doe" --max-pages 60
# or best: pass the thread id from the inbox URL
node cli.js linkedin salesnav-thread "5918503635263671296"
Defensive patterns

Strategy: try-catch

Validate before calling

const exact = /^\d+$/.test(input) || input.includes('/inbox/') || input.startsWith('urn:li:');

Type guard

null

Try / catch

try { thread = await threadId(input) } catch (e) { if (e instanceof EmptyResultError) { /* widen search: raise --max-pages or use exact thread id */ } else throw e; }

Prevention

When it happens

Trigger: Calling linkedin salesnav-thread with a participant name spelled differently than in Sales Navigator, a lead URL whose lead has no thread in the signed-in account's inbox, or a recipient URN not present in the first 500 inbox rows (maxPages exhausted).

Common situations: Typo or different display-name casing in the participant name; messaging a lead who has never replied so the thread is not in the default inbox view; the account owns thousands of threads so the target is beyond the 500-row/30-page scan limit; signed into the wrong LinkedIn account.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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