{"record":{"id":"7d0755ebec7ea886","repo":"jackwener/OpenCLI","slug":"label-is-required-7d0755","errorCode":null,"errorMessage":"${label} is required","messagePattern":"(.+?) is required","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/salesnav-message.js","lineNumber":17,"sourceCode":"import { cli, Strategy } from '@jackwener/opencli/registry';\nimport { ArgumentError, AuthRequiredError, CommandExecutionError } from '@jackwener/opencli/errors';\nimport { unwrapEvaluateResult } from './shared.js';\n\nconst LINKEDIN_DOMAIN = 'www.linkedin.com';\nconst SALES_HOME = 'https://www.linkedin.com/sales/';\nconst PROFILE_DECO = '(entityUrn,objectUrn,firstName,lastName,fullName,headline,degree,inmailRestriction,memberBadges,defaultPosition)';\nconst CREDITS_URL = 'https://www.linkedin.com/sales-api/salesApiCredits?q=findCreditGrant&creditGrantType=LSS_INMAIL';\nconst MESSAGE_ACTION_URL = 'https://www.linkedin.com/sales-api/salesApiMessageActions?action=createMessage';\n\nfunction normalizeWhitespace(value) {\n  return String(value ?? '').replace(/[\\u00a0\\u202f]/g, ' ').replace(/\\s+/g, ' ').trim();\n}\n\nfunction requireStringArg(args, key, label = key) {\n  const value = normalizeWhitespace(args[key]);\n  if (!value) throw new ArgumentError(`${label} is required`);\n  return value;\n}\n\nfunction isLinkedInHost(hostname) {\n  const host = String(hostname || '').toLowerCase();\n  return host === 'linkedin.com' || host.endsWith('.linkedin.com');\n}\n\nfunction parseSalesProfileUrn(value) {\n  const raw = normalizeWhitespace(value);\n  const match = raw.match(/^urn:li:fs_salesProfile:\\(([^,()]+),([^,()]+),([^,()]+)\\)$/);\n  if (!match) return null;\n  if (!isResolvedSalesProfileParts(match[1], match[2], match[3])) return null;\n  return { profileId: match[1], authType: match[2], authToken: match[3], entityUrn: raw };\n}\n\nfunction isResolvedSalesProfileParts(profileId, authType, authToken) {\n  return [profileId, authType, authToken].every((part) => {","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/salesnav-message.js#L1-L35","documentation":"requireStringArg normalizes an argument (collapsing whitespace/nbsp and trimming) and throws ArgumentError if nothing remains. It guarantees that required string CLI arguments are non-empty before any work is done.","triggerScenarios":"Calling code (e.g. recipientArg, subject) reads args[key] and the value is undefined, empty string, or only whitespace/non-breaking spaces after normalization.","commonSituations":"Forgetting --recipient or --subject on the salesnav-message command line; passing quoted empty strings; a value consisting solely of spaces or non-breaking-space characters pasted from rich text.","solutions":["Supply the missing argument explicitly, e.g. --recipient \"urn:li:fs_salesProfile:(...)\" --subject \"Hello\".","Check shell quoting so the value is not swallowed or split by the shell.","Strip stray whitespace/nbsp from the value before passing it."],"exampleFix":"// before\nlinkedin salesnav-message --body \"hi\"\n// after\nlinkedin salesnav-message --recipient \"urn:li:fs_salesProfile:(urn:li:person:ABC,123)\" --subject \"Hi\" --body \"hi\"","handlingStrategy":"validation","validationCode":"function isFilled(v) { return String(v ?? '').replace(/[\\u00a0\\u202f]/g, ' ').replace(/\\s+/g, ' ').trim().length > 0; }\nif (!isFilled(args.recipient)) throw new Error('pass a non-empty --recipient');\nif (!isFilled(args.subject)) throw new Error('pass a non-empty --subject');","typeGuard":"function isNonEmptyString(v) { return typeof v === 'string' && v.trim().length > 0; }","tryCatchPattern":"try { await sendMessage(args); } catch (e) { if (e instanceof ArgumentError && /is required$/.test(e.message)) { console.error(`Missing argument: ${e.message}`); process.exitCode = 2; } else throw e; }","preventionTips":["Always pass --recipient and --subject explicitly on the CLI.","Quote arguments so shells don't strip whitespace-only values.","Sanitize inputs from rich-text sources (nbsp, tabs).","Validate all required args in a wrapper before invoking the command."],"tags":["argument-validation","cli","input"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}