{"record":{"id":"63d1379ea33cf4d9","repo":"paperclipai/paperclip","slug":"chat-provider-pretransport-rejected","errorCode":"CHAT_PROVIDER_PRETRANSPORT_REJECTED","errorMessage":"Invalid GitHub receipt destination","messagePattern":"Invalid GitHub receipt destination","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/chat-github-receipt-reactions.ts","lineNumber":88,"sourceCode":"  input: GitHubReceiptMutation,\n  assertCurrent: () => Promise<void>,\n  fetchImpl: typeof globalThis.fetch = globalThis.fetch,\n): Promise<GitHubReceiptIdentity> {\n  const adapter = adapterValue as Adapter;\n  if (\n    !adapter ||\n    typeof adapter.decodeThreadId !== \"function\" ||\n    !numericId(appId) ||\n    !numericId(installationId) ||\n    !numericId(input.messageId) ||\n    input.reaction !== \"eyes\" ||\n    ![\"add\", \"remove\"].includes(input.operation) ||\n    !/^github:[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+:(?:issue:)?[1-9][0-9]*(?::rc:[1-9][0-9]*)?$/.test(\n      input.threadId,\n    )\n  ) {\n    throw Object.assign(new Error(\"Invalid GitHub receipt destination\"), {\n      code: \"CHAT_PROVIDER_PRETRANSPORT_REJECTED\",\n    });\n  }\n  const destination = adapter.decodeThreadId(input.threadId);\n  if (\n    !/^[A-Za-z0-9][A-Za-z0-9-]{0,38}$/.test(destination.owner) ||\n    !/^[A-Za-z0-9_.-]{1,100}$/.test(destination.repo) ||\n    [\".\", \"..\"].includes(destination.repo) ||\n    !numericId(destination.prNumber) ||\n    (destination.reviewCommentId !== undefined &&\n      !numericId(destination.reviewCommentId))\n  ) {\n    throw Object.assign(new Error(\"Invalid GitHub receipt destination\"), {\n      code: \"CHAT_PROVIDER_PRETRANSPORT_REJECTED\",\n    });\n  }\n  const client = adapter.octokit;\n  if (typeof client?.auth !== \"function\") throw unavailable(\"adapter_contract\");\n  const expected =","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-github-receipt-reactions.ts#L70-L106","documentation":"applyGitHubReceiptReaction validates its inputs before any network call. If the adapter lacks decodeThreadId, appId/installationId/messageId are not numeric, the reaction is not \"eyes\", the operation is not add/remove, or threadId does not match the strict pattern ^github:owner/repo:(issue:)?N(:rc:N)?$ (chat-github-receipt-reactions.ts:83-89), it throws Error(\"Invalid GitHub receipt destination\") with code CHAT_PROVIDER_PRETRANSPORT_REJECTED. This pre-transport guard guarantees only well-formed GitHub thread destinations ever reach the reaction API.","triggerScenarios":"Calling applyGitHubReceiptReaction with a threadId like \"github:owner/repo:0\" (zero not allowed), a missing github: prefix, a malformed review-comment segment, or a non-numeric appId/installationId/messageId; passing a wrong/partial adapter object.","commonSituations":"Constructing threadIds by string concatenation with unpadded/zero IDs; decoding failures upstream producing altered threadId strings; older adapters without decodeThreadId being passed to this new API; copying threadIds from other providers (slack:, discord:) into the GitHub receipt path.","solutions":["Format threadId exactly as github:<owner>/<repo>:<prNumber> or with optional issue:/rc: segments using positive integers","Verify the adapter passed in implements decodeThreadId (use the pinned GitHub adapter)","Check that appId, installationId, and messageId are numeric IDs as strings/numbers without decoration","Log the rejected input and compare it against the accepted regex to find the mismatched segment"],"exampleFix":"// before\nawait applyGitHubReceiptReaction(adapter, appId, installationId, { threadId: \"github:org/repo:pr/123\", reaction: \"eyes\", operation: \"add\", ... });\n// after\nawait applyGitHubReceiptReaction(adapter, appId, installationId, { threadId: \"github:org/repo:123\", reaction: \"eyes\", operation: \"add\", ... });","handlingStrategy":"validation","validationCode":"const THREAD_RE = /^github:[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+:(?:issue:)?[1-9][0-9]*(?::rc:[1-9][0-9]*)?$/; if (!THREAD_RE.test(threadId) || !numericId(appId) || !numericId(installationId) || !numericId(messageId)) throw new Error(\"invalid receipt destination\");","typeGuard":"function isGitHubReceiptInput(x) { return typeof x?.threadId === \"string\" && /^github:[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+:(?:issue:)?[1-9][0-9]*(?::rc:[1-9][0-9]*)?$/.test(x.threadId) && (x.reaction === \"eyes\") && [\"add\",\"remove\"].includes(x.operation); }","tryCatchPattern":"try { await applyGitHubReceiptReaction(adapter, appId, installationId, input, assertCurrent); } catch (e) { if (e?.code === \"CHAT_PROVIDER_PRETRANSPORT_REJECTED\") { logInvalidDestination(input); return; } throw e; }","preventionTips":["Build threadIds from a single formatting helper, never string concatenation","Only positive integers (no leading-zero/zero IDs) in issue/pr/rc segments","Pass the pinned adapter that implements decodeThreadId","Unit-test threadId formatting against the accepted regex"],"tags":["github","validation","thread-id","pretransport"],"backgroundTag":"invalid-argument-format","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}