{"record":{"id":"aa52b34430656d1e","repo":"jackwener/OpenCLI","slug":"recipient-must-be-a-sales-navigator-lead-url-sa","errorCode":null,"errorMessage":"--recipient must be a Sales Navigator lead URL, Sales Navigator profile URL, LinkedIn /in/ URL, or urn:li:fs_salesProfile:(...)","messagePattern":"--recipient must be a Sales Navigator lead URL, Sales Navigator profile URL, LinkedIn /in/ URL, or urn:li:fs_salesProfile:\\(\\.\\.\\.\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/salesnav-message.js","lineNumber":191,"sourceCode":"  return result;\n}\n\nfunction salesPageShowsSentMessage(text, recipientName) {\n  const normalizedText = normalizeWhitespace(text);\n  const firstName = normalizeWhitespace(recipientName).split(' ')[0];\n  return normalizedText.includes('You sent a Sales Navigator message')\n    && (!firstName || normalizedText.includes(firstName));\n}\n\nasync function getCsrf(page) {\n  const cookies = await page.getCookies({ url: 'https://www.linkedin.com' });\n  const jsession = cookies.find((c) => c.name === 'JSESSIONID')?.value;\n  if (!jsession) throw new AuthRequiredError(LINKEDIN_DOMAIN, 'LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn.');\n  return jsession.replace(/^\\\"|\\\"$/g, '');\n}\n\nasync function resolveRecipient(page, parsed, csrf) {\n  if (!parsed) throw new ArgumentError('--recipient must be a Sales Navigator lead URL, Sales Navigator profile URL, LinkedIn /in/ URL, or urn:li:fs_salesProfile:(...)');\n  if (parsed.entityUrn && parsed.authType && parsed.authToken) return parsed;\n\n  await page.goto(`https://www.linkedin.com/sales/lead/${encodeURIComponent(parsed.profileId)}`);\n  await page.wait(6);\n  const probe = unwrapEvaluateResult(await page.evaluate(String.raw`(() => {\n    const href = location.href;\n    const text = document.body ? document.body.innerText : '';\n    const resourceUrns = Array.from(performance.getEntriesByType('resource'))\n      .map((entry) => entry.name)\n      .filter((name) => name.includes('/sales-api/salesApiProfiles/'))\n      .slice(-20);\n    return { href, text: text.slice(0, 1000), resourceUrns };\n  })()`));\n    const urlMatch = String(probe?.href || '').match(/\\/sales\\/lead\\/([^,/]+),([^,/]+),([^/?#]+)/i);\n  if (urlMatch && isResolvedSalesProfileParts(urlMatch[1], urlMatch[2], urlMatch[3])) {\n    return {\n      profileId: decodeURIComponent(urlMatch[1]),\n      authType: decodeURIComponent(urlMatch[2]),","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/salesnav-message.js#L173-L209","documentation":"resolveRecipient throws ArgumentError when the --recipient argument could not be parsed into any supported form (Sales Nav lead URN, Sales Nav lead URL, /in/ profile URL, or a resolvable salesProfile urn). parseRecipient returned null/undefined for the supplied value.","triggerScenarios":"Passing --recipient values like a plain name, a non-https URL, a non-LinkedIn URL, a malformed urn:li:fs_salesProfile triple (missing parts or 'undefined'/'null' placeholders), or forgetting the flag entirely (requireStringArg yields nothing to parse).","commonSituations":"Copying a public LinkedIn company URL instead of a person profile; pasting a truncated URN; using a sales lead URL with placeholder auth segments; typos or extra whitespace/quotes in the argument.","solutions":["Provide a valid Sales Navigator lead URL, LinkedIn /in/ URL, or full urn:li:fs_salesProfile:(id,authType,authToken)","Copy the URN from Sales Navigator (not a regular LinkedIn feed URL)","Ensure all three urn segments are present and not 'undefined'/'null'","Quote the argument in your shell to avoid truncation"],"exampleFix":"// before\n--recipient \"Jane Doe\"\n// after\n--recipient \"https://www.linkedin.com/in/jane-doe/\"","handlingStrategy":"validation","validationCode":"const RE = /^urn:li:fs_salesProfile:\\(([^,()]+),([^,()]+),([^,()]+)\\)$/;\nconst SALES_URL = /^https:\\/\\/www\\.linkedin\\.com\\/sales\\/lead\\/[^,/]+,[^,/]+,[^/]+\\/?$/i;\nconst IN_URL = /^https:\\/\\/www\\.linkedin\\.com\\/in\\/[^/]+\\/?$/i;\nif (!(RE.test(v) || SALES_URL.test(v) || IN_URL.test(v))) throw new Error('Unsupported --recipient format: ' + v);","typeGuard":"const isValidRecipient = (v) =>\n  typeof v === 'string' && (\n    /^urn:li:fs_salesProfile:\\([^,()]+,[^,()]+,[^,()]+\\)$/.test(v.trim()) ||\n    /^https:\\/\\/(www\\.)?linkedin\\.com\\/(sales\\/lead\\/[^/]+|in\\/[^/]+)\\/?$/i.test(v.trim())\n  );","tryCatchPattern":"try {\n  await sendMessage(page, { recipient: argv.recipient });\n} catch (err) {\n  if (err instanceof ArgumentError && err.message.startsWith('--recipient')) {\n    console.error('Use a Sales Nav lead URL, /in/ URL, or full salesProfile urn');\n  } else throw err;\n}","preventionTips":["Copy recipients straight from Sales Navigator, not the feed","Ensure all three urn segments are populated (no 'undefined'/'null')","Quote the flag value in shell to avoid truncation","Reject non-https or non-linkedin URLs before calling"],"tags":["argument-validation","linkedin","sales-navigator","bad-input"],"backgroundTag":"invalid-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}