{"record":{"id":"da5640f0bc6dc5bb","repo":"paperclipai/paperclip","slug":"github-attachment-source-mismatch-da5640","errorCode":"github_attachment_source_mismatch","errorMessage":"github_attachment_source_mismatch","messagePattern":"github_attachment_source_mismatch","errorType":"exception","errorClass":"GitHubAttachmentUnavailableError","httpStatus":null,"severity":"error","filePath":"server/src/services/chat-sdk-runtime.ts","lineNumber":2839,"sourceCode":"    signal: AbortSignal,\n  ): Promise<Buffer> {\n    const fetcher = this.teamsInlineImageFetchers.get(attachment);\n    if (!fetcher || signal.aborted)\n      throw new Error(\"Teams inline image download unavailable\");\n    return await fetcher(signal);\n  }\n\n  /** Called only after current inbound admission; installation App authority only. */\n  async resolveGitHubAttachmentComment(\n    request: GitHubAttachmentCommentRequest,\n    signal: AbortSignal,\n  ): Promise<unknown> {\n    if (!this.githubAttachmentAppAuthority)\n      throw new GitHubAttachmentUnavailableError(\n        \"github_attachment_canonical_authority_unavailable\",\n      );\n    if (!isGitHubAttachmentCommentRequest(request))\n      throw new GitHubAttachmentUnavailableError(\n        \"github_attachment_source_mismatch\",\n      );\n    try {\n      signal.throwIfAborted();\n      const result = await (this.adapter as GitHubAdapter).octokit.request(\n        `GET ${request.url}`,\n        {\n          headers: {\n            accept: request.accept,\n            \"x-github-api-version\": \"2022-11-28\",\n          },\n          request: {\n            signal,\n            redirect: \"manual\",\n            fetch: githubAttachmentCommentFetch(request, signal),\n          },\n        },\n      );","sourceCodeStart":2821,"sourceCodeEnd":2857,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-sdk-runtime.ts#L2821-L2857","documentation":"After checking App authority, resolveGitHubAttachmentComment validates the request shape with isGitHubAttachmentCommentRequest. A request that is not a recognized GitHub attachment comment request (wrong origin, malformed fields, or a URL/attachment from another provider) causes GitHubAttachmentUnavailableError('github_attachment_source_mismatch'), signaling the request does not correspond to a canonical GitHub source this runtime can resolve.","triggerScenarios":"Passing a GitHubAttachmentCommentRequest whose payload fails isGitHubAttachmentCommentRequest validation — e.g. an attachment captured from Slack/Teams reused here, a hand-built request missing required GitHub fields, or a URL outside the expected GitHub domain/repo.","commonSituations":"Cross-provider attachment handling bugs; schema drift after shared-type updates so older persisted requests no longer validate; constructing the request manually instead of from admitted inbound data.","solutions":["Build the GitHubAttachmentCommentRequest from the admitted inbound attachment data, not manually","Verify the attachment origin is GitHub and the URL matches the expected GitHub API shape","Regenerate/re-admit the request if persisted data predates a validator/schema change","Confirm you are calling the GitHub resolver with GitHub-sourced attachments only"],"exampleFix":"// before\nawait runtime.resolveGitHubAttachmentComment({ url: someUrl } as any, signal);\n// after\nif (isGitHubAttachmentCommentRequest(req)) {\n  await runtime.resolveGitHubAttachmentComment(req, signal);\n}","handlingStrategy":"validation","validationCode":"if (!isGitHubAttachmentCommentRequest(request)) throw new Error('not a GitHub attachment comment request');","typeGuard":"const isGitHubAttachmentCommentRequest = (r: unknown): r is GitHubAttachmentCommentRequest => typeof r === 'object' && r !== null && typeof (r as any).url === 'string' && (r as any).url.startsWith('https://api.github.com/');","tryCatchPattern":"try { return await runtime.resolveGitHubAttachmentComment(request, signal); } catch (e) { if ((e as Error).message === 'github_attachment_source_mismatch') { /* rebuild request from admitted inbound data */ } else throw e; }","preventionTips":["Construct requests only from admitted inbound attachment data","Re-validate persisted requests after shared-type/validator changes","Never reuse attachment request objects across chat providers"],"tags":["github","validation","attachments","source-mismatch"],"backgroundTag":"schema-validation-failed","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}