{"record":{"id":"1486d8d81567d062","repo":"paperclipai/paperclip","slug":"external-chat-text-exceeds-its-processing-limit","errorCode":null,"errorMessage":"External chat text exceeds its processing limit","messagePattern":"External chat text exceeds its processing limit","errorType":"validation","errorClass":"UnsafeChatPublicationError","httpStatus":null,"severity":"error","filePath":"server/src/services/chat-publication-projection.ts","lineNumber":245,"sourceCode":"      (_match, label: string, separator: string) =>\n        `${label}${separator}[REDACTED]`,\n    )\n    .replace(CONNECTION_STRING_RE, \"[REDACTED]\");\n}\n\nfunction truncateByCodePoint(input: string, limit: number): string {\n  if (input.length <= limit) return input;\n  return Array.from(input).slice(0, limit).join(\"\");\n}\n\n/**\n * The only text projection allowed to cross from Paperclip into a provider.\n * It strips internal reasoning/tool/log content, redacts credentials, removes\n * dangerous or token-bearing links, and neutralizes provider-wide mentions.\n */\nexport function projectSafeChatPublicationText(input: string): string {\n  if (input.length > MAX_TEXT_INPUT_LENGTH) {\n    throw new UnsafeChatPublicationError(\n      \"External chat text exceeds its processing limit\",\n    );\n  }\n  let output = input.replace(/<\\|[^|\\r\\n]{1,80}\\|>/g, \"\");\n  for (const pattern of HIDDEN_BLOCKS) output = output.replace(pattern, \"\");\n  output = stripHiddenSections(output);\n  // Strip token-bearing query strings before the general credential scanner.\n  // That scanner deliberately consumes uncertain unquoted values aggressively;\n  // running it first could eat the visible prose following a Markdown URL.\n  output = sanitizeUrls(output);\n  output = sanitizeCredentialText(output);\n  output = output\n    .replace(SLACK_BROADCAST_RE, (_match, name: string) => `@\\u200b${name}`)\n    .replace(PROVIDER_BROADCAST_RE, (_match, name: string) => `@\\u200b${name}`)\n    .replace(/[ \\t]+\\n/g, \"\\n\")\n    .replace(/\\n{3,}/g, \"\\n\\n\")\n    .trim();\n","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/chat-publication-projection.ts#L227-L263","documentation":"projectSafeChatPublicationText is the only text path allowed from Paperclip into an external chat provider, and it bounds its sanitization work by rejecting inputs over MAX_TEXT_INPUT_LENGTH (1,000,000 UTF-16 units) with an UnsafeChatPublicationError. The limit protects against pathological redaction/regex workloads; it bounds processing, not delivery — shorter text may still expand during redaction and that is allowed.","triggerScenarios":"Calling projectSafeChatPublicationText (directly or via receipt/enqueueResponse/projected/title/body helpers) with input text whose .length exceeds 1,000,000 — e.g. concatenating an entire issue thread or pasting a huge log dump as a chat reply.","commonSituations":"An automation forwarding giant build logs or file dumps to a chat provider; a runaway agent appending unbounded context into the response text; aggregating many comments into one message body.","solutions":["Truncate or summarize the text below 1,000,000 characters before projecting (keep the most recent/relevant portion).","Split the content into multiple smaller chat messages.","Attach large content as files/attachments (MAX_ATTACHMENTS = 20) instead of inline text.","If this happens systematically, fix the producer that concatenates unbounded content into one publication."],"exampleFix":"// before\nawait enqueueResponse(issueId, wholeThreadText); // throws if > 1M chars\n// after\nconst MAX = 1_000_000;\nconst text = wholeThreadText.length > MAX\n  ? \"…\" + wholeThreadText.slice(-MAX + 1000) // keep the tail, note truncation\n  : wholeThreadText;\nawait enqueueResponse(issueId, text);","handlingStrategy":"validation","validationCode":"const MAX = 1_000_000;\nif (text.length > MAX) {\n  text = text.slice(0, MAX - 20) + \"\\n[truncated]\"; // or split into parts\n}","typeGuard":"null","tryCatchPattern":"try { return projectSafeChatPublicationText(input); }\ncatch (e) {\n  if (e instanceof UnsafeChatPublicationError || e.message.includes(\"exceeds its processing limit\")) {\n    return projectSafeChatPublicationText(truncate(input, 1_000_000));\n  }\n  throw e;\n}","preventionTips":["Bound producer output before it reaches the projection layer","Split very large content into multiple messages or attachments","Summarize logs/threads instead of forwarding them verbatim","Alert on message-size growth in agent response pipelines"],"tags":["input-validation","chat","size-limit"],"backgroundTag":"value-out-of-range","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}