{"record":{"id":"7b6a47227e23e94c","repo":"paperclipai/paperclip","slug":"github-attachment-canonical-authority-unavailable","errorCode":"github_attachment_canonical_authority_unavailable","errorMessage":"github_attachment_canonical_authority_unavailable","messagePattern":"github_attachment_canonical_authority_unavailable","errorType":"exception","errorClass":"GitHubAttachmentUnavailableError","httpStatus":null,"severity":"error","filePath":"server/src/services/chat-sdk-runtime.ts","lineNumber":2835,"sourceCode":"\n  /** Only attachments reconstructed by this runtime can use the batch budget. */\n  async fetchTeamsInlineImage(\n    attachment: Attachment,\n    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\",","sourceCodeStart":2817,"sourceCodeEnd":2853,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-sdk-runtime.ts#L2817-L2853","documentation":"resolveGitHubAttachmentComment performs a canonical GitHub API request using the installation-scoped GitHub App authority captured during inbound admission. It throws GitHubAttachmentUnavailableError('github_attachment_canonical_authority_unavailable') when the runtime has no githubAttachmentAppAuthority, i.e. the installation credential needed to act with App authority is absent.","triggerScenarios":"Calling resolveGitHubAttachmentComment on a runtime constructed without the GitHub attachment App authority (missing GitHub App installation credential for the repo), typically because admission never captured it or the runtime was built outside the GitHub inbound path.","commonSituations":"GitHub App uninstalled or installation token not refreshed; runtime reconstructed (e.g. after restart) without the attachment authority; attachment resolution invoked from a non-GitHub endpoint's runtime.","solutions":["Ensure the runtime is constructed with githubAttachmentAppAuthority from the GitHub App installation during inbound admission","Verify the GitHub App installation is still active and its token can be minted for the target repository","Re-admit the message so a fresh authority is captured, then retry attachment resolution","Route the call through the GitHub runtime that owns the admission, not an arbitrary runtime"],"exampleFix":"// before\nconst data = await runtime.resolveGitHubAttachmentComment(request, signal);\n// after\nif (runtime.hasGitHubAttachmentAuthority()) {\n  const data = await runtime.resolveGitHubAttachmentComment(request, signal);\n}","handlingStrategy":"validation","validationCode":"if (!runtime.hasGitHubAttachmentAuthority()) throw new Error('GitHub attachment authority not provisioned');","typeGuard":"const hasAuthority = (r: ChatSdkRuntime) => r.githubAttachmentAppAuthority != null;","tryCatchPattern":"try { return await runtime.resolveGitHubAttachmentComment(request, signal); } catch (e) { if ((e as Error).message === 'github_attachment_canonical_authority_unavailable') { /* re-admit message to capture authority */ } else throw e; }","preventionTips":["Capture the GitHub App installation authority during inbound admission","Monitor installation status so revoked installations are detected early","Only call attachment resolution on the runtime that performed the admission"],"tags":["github","attachments","missing-credentials","app-installation"],"backgroundTag":"missing-credentials","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"}