{"record":{"id":"81dd4dab742f0604","repo":"jackwener/OpenCLI","slug":"no-sales-navigator-thread-matched-input","errorCode":null,"errorMessage":"No Sales Navigator thread matched ${input}","messagePattern":"No Sales Navigator thread matched (.+?)","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/salesnav-thread.js","lineNumber":143,"sourceCode":"    return (row.participants || []).some((p) => normalizeWhitespace(p.entity_urn) === criterion);\n  }\n  if (kind === 'name') {\n    const needle = normalizeWhitespace(criterion).toLowerCase();\n    if (!needle) return false;\n    if (normalizeWhitespace(row.person_name).toLowerCase() === needle) return true;\n    return (row.participants || []).some((p) => normalizeWhitespace(p.name).toLowerCase() === needle);\n  }\n  return false;\n}\n\nasync function resolveThreadId(page, input, { maxPages = 30 } = {}) {\n  const parsed = parseThreadInput(input);\n  if (parsed[0] === 'empty') throw new ArgumentError('thread or recipient is required');\n  if (parsed[0] === 'thread_id') return parsed[1];\n  const inboxRows = await fetchInboxRows(page, { limit: 500, maxPages });\n  const match = inboxRows.find((row) => threadMatchesInput(row, parsed));\n  if (!match) {\n    throw new EmptyResultError('linkedin salesnav-thread', `No Sales Navigator thread matched ${input}`);\n  }\n  return match.thread_id;\n}\n\nasync function fetchThreadWithPagination(page, csrf, threadId, limit = DEFAULT_MESSAGE_LIMIT) {\n  let requested = THREAD_PAGE_SIZE;\n  if (limit < requested) requested = limit;\n  let thread = null;\n  for (let attempts = 0; attempts < 30; attempts += 1) {\n    thread = await fetchSalesnavJson(page, csrf, threadApiUrl(threadId, requested), 'Sales Navigator messaging thread API');\n    const total = Number(thread?.totalMessageCount || 0);\n    const have = Array.isArray(thread?.messages) ? thread.messages.length : 0;\n    if (have >= limit || (total && have >= total) || requested >= limit) break;\n    let nextRequested = requested + THREAD_PAGE_SIZE;\n    if (total && total > nextRequested) nextRequested = total;\n    if (nextRequested > limit) nextRequested = limit;\n    requested = nextRequested;\n  }","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/salesnav-thread.js#L125-L161","documentation":"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'.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Pass the numeric Sales Navigator thread id (from the inbox URL) directly instead of a name so resolution is skipped.","Verify the exact participant name matches Sales Navigator (copy/paste it).","Increase --max-pages so more inbox pages are scanned before giving up.","Confirm you are signed into the LinkedIn account that actually owns the conversation.","Open the thread in Sales Navigator and pass its inbox URL."],"exampleFix":"// before\nnode cli.js linkedin salesnav-thread \"Jane Doe\"        # fuzzy name miss\n// after\nnode cli.js linkedin salesnav-thread \"Jane Doe\" --max-pages 60\n# or best: pass the thread id from the inbox URL\nnode cli.js linkedin salesnav-thread \"5918503635263671296\"","handlingStrategy":"try-catch","validationCode":"const exact = /^\\d+$/.test(input) || input.includes('/inbox/') || input.startsWith('urn:li:');","typeGuard":"null","tryCatchPattern":"try { thread = await threadId(input) } catch (e) { if (e instanceof EmptyResultError) { /* widen search: raise --max-pages or use exact thread id */ } else throw e; }","preventionTips":["Pass the numeric thread id from the Sales Navigator inbox URL whenever available.","Copy participant names exactly from Sales Navigator instead of retyping them.","Increase --max-pages when the account has a large inbox.","Confirm the browser session is signed into the account that owns the conversation."],"tags":["empty-result","linkedin","sales-navigator","search-failed"],"backgroundTag":"empty-result-set","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}