{"record":{"id":"b2fb4f6ce506c86e","repo":"jackwener/OpenCLI","slug":"thread-or-recipient-is-required-b2fb4f","errorCode":null,"errorMessage":"thread-or-recipient is required","messagePattern":"thread-or-recipient is required","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/salesnav-thread.js","lineNumber":187,"sourceCode":"\ncli({\n  site: 'linkedin',\n  name: 'salesnav-thread',\n  access: 'read',\n  description: 'Return full Sales Navigator message history for a thread id, Sales Navigator inbox URL, lead URL, recipient urn, or exact recipient name',\n  domain: LINKEDIN_DOMAIN,\n  strategy: Strategy.UI,\n  browser: true,\n  args: [\n    { 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' },\n    { name: 'limit', type: 'number', default: DEFAULT_MESSAGE_LIMIT, help: 'Maximum messages to return (1-500)' },\n    { name: 'max-pages', type: 'number', default: 30, help: 'Maximum inbox pages to scan when resolving a recipient' },\n  ],\n  columns: ['index', 'thread_id', 'thread_url', 'sender', 'text', 'timestamp', 'subject', 'message_id', 'sender_urn', 'delivered_at', 'type', 'total_message_count'],\n  func: async (page, args) => {\n    if (!page) throw new CommandExecutionError('Browser session required for linkedin salesnav-thread');\n    const input = normalizeWhitespace(args['thread-or-recipient']);\n    if (!input) throw new ArgumentError('thread-or-recipient is required');\n    const limit = parseLimit(args.limit, DEFAULT_MESSAGE_LIMIT);\n    const maxPages = parseLimit(args['max-pages'], 30);\n    await page.goto(SALES_INBOX_URL);\n    await page.wait(4);\n    const threadId = await resolveThreadId(page, input, { maxPages });\n    const csrf = await getCsrf(page);\n    const thread = await fetchThreadWithPagination(page, csrf, threadId, limit);\n    const messages = parseSalesnavThreadMessages(thread).slice(0, limit);\n    if (messages.length === 0) throw new EmptyResultError('linkedin salesnav-thread', `No messages found for ${threadId}`);\n    return messages.map((message) => ({\n      ...message,\n      thread_url: salesnavThreadUrl(threadId),\n      total_message_count: Number(thread?.totalMessageCount || messages.length),\n    }));\n  },\n});\n\nexport const __test__ = {","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/salesnav-thread.js#L169-L205","documentation":"The command's func normalizes the positional 'thread-or-recipient' argument with normalizeWhitespace; if the result is an empty string it throws ArgumentError('thread-or-recipient is required'). This is the top-level argument check and mirrors the deeper resolveThreadId 'empty' guard (error 2400) but fires before any page navigation.","triggerScenarios":"Invoking linkedin salesnav-thread with no positional argument, an empty string, or a whitespace-only string.","commonSituations":"Forgetting the positional argument on the command line; a build script interpolating an empty variable; quoting mistakes so the shell drops the argument; passing args as named flags instead of the required positional.","solutions":["Provide the positional thread-or-recipient value (inbox URL, thread id, lead URL, recipient URN, or participant name).","Trim the value; whitespace-only input is rejected.","Guard calling scripts so they abort when the value is empty.","Use the CLI's --help to confirm the positional arity."],"exampleFix":"// before\nnode cli.js linkedin salesnav-thread            # missing positional\n// after\nnode cli.js linkedin salesnav-thread \"https://www.linkedin.com/sales/inbox/5918503635263671296\"","handlingStrategy":"validation","validationCode":"const v = (args['thread-or-recipient'] ?? '').trim(); if (!v) throw new Error('usage: linkedin salesnav-thread <inbox-url|thread-id|lead-url|urn|name>');","typeGuard":"function isNonEmptyString(v){ return typeof v === 'string' && v.trim().length > 0; }","tryCatchPattern":"try { await cli() } catch (e) { if (e instanceof ArgumentError && e.message === 'thread-or-recipient is required') { process.exitCode = 2; console.error(e.message); } else throw e; }","preventionTips":["Quote the positional argument in shell scripts so it is never dropped.","Guard interpolated variables for emptiness before invocation.","Document the positional in wrapper scripts and validate there first.","Use --help to confirm argument arity before scripting."],"tags":["argument-error","cli","input-validation","linkedin"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}