{"record":{"id":"b3d846a32923af17","repo":"jackwener/OpenCLI","slug":"subject-must-be-200-characters-or-fewer","errorCode":null,"errorMessage":"--subject must be 200 characters or fewer","messagePattern":"--subject must be 200 characters or fewer","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/salesnav-message.js","lineNumber":94,"sourceCode":"  const key = `(profileId:${recipient.profileId},authType:${recipient.authType},authToken:${recipient.authToken})`;\n  return `https://www.linkedin.com/sales-api/salesApiProfiles/${key}?decoration=${encodeRestliDecoration(PROFILE_DECO)}`;\n}\n\nfunction randomTrackingId() {\n  const bytes = new Uint8Array(8);\n  if (globalThis.crypto?.getRandomValues) globalThis.crypto.getRandomValues(bytes);\n  else for (let i = 0; i < bytes.length; i += 1) bytes[i] = Math.floor(Math.random() * 256);\n  return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\nfunction buildCreateMessagePayload({ recipientUrn, subject, body, trackingId = randomTrackingId(), copyToCrm = false }) {\n  const cleanRecipient = normalizeWhitespace(recipientUrn);\n  if (!parseSalesProfileUrn(cleanRecipient)) throw new ArgumentError('--recipient must resolve to a Sales Navigator lead urn');\n  const cleanSubject = normalizeWhitespace(subject);\n  const cleanBody = String(body ?? '').trim();\n  if (!cleanSubject) throw new ArgumentError('--subject is required');\n  if (!cleanBody) throw new ArgumentError('--body is required');\n  if (cleanSubject.length > 200) throw new ArgumentError('--subject must be 200 characters or fewer');\n  if (cleanBody.length > 1900) throw new ArgumentError('--body must be 1900 characters or fewer');\n  return {\n    createMessageRequest: {\n      recipients: [cleanRecipient],\n      subject: cleanSubject,\n      body: cleanBody,\n      copyToCrm: Boolean(copyToCrm),\n      trackingId,\n    },\n  };\n}\n\nfunction extractRemainingCredits(json) {\n  const elements = Array.isArray(json?.elements) ? json.elements : [];\n  const inmailGrant = elements.find((el) => el?.type === 'LSS_INMAIL' && Number.isInteger(el.value));\n  if (inmailGrant) return inmailGrant.value;\n  const candidates = [];\n  const visit = (value) => {","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/salesnav-message.js#L76-L112","documentation":"buildCreateMessagePayload enforces a maximum subject length of 200 characters (after normalization). Subjects exceeding that limit would be rejected by the Sales Navigator API, so the library fails fast with ArgumentError.","triggerScenarios":"cleanSubject.length > 200 — a subject longer than 200 characters after whitespace normalization.","commonSituations":"Auto-generated or templated subjects (long job titles, merged fields) exceeding the cap; pasted rich text with extra non-breaking spaces inflating length.","solutions":["Shorten the subject to 200 characters or fewer.","Collapse excessive whitespace before sending (the library normalizes nbsp, so pre-trim your template).","Truncate programmatically: subject.slice(0, 200) with ellipsis if acceptable."],"exampleFix":"// before\nconst subject = veryLongTemplate;\n// after\nconst subject = veryLongTemplate.length > 200 ? veryLongTemplate.slice(0, 197) + '...' : veryLongTemplate;","handlingStrategy":"validation","validationCode":"if ([...String(subject).replace(/[\\u00a0\\u202f]/g,' ')].length > 200) subject = subject.slice(0, 200);","typeGuard":null,"tryCatchPattern":"try { await sendMessage({ subject, body }); } catch (e) { if (/subject must be 200 characters or fewer/.test(e.message)) { subject = subject.slice(0, 200); /* retry */ } else throw e; }","preventionTips":["Keep templated subjects under 200 chars by design.","Truncate with ellipsis at generation time.","Collapse whitespace before measuring length.","Unit-test subject templates for length."],"tags":["argument-validation","limits","input"],"backgroundTag":"input-length-limit-exceeded","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}