{"record":{"id":"c2150e01c02bccf8","repo":"paperclipai/paperclip","slug":"github-attachment-canonical-anchor-missing","errorCode":"github_attachment_canonical_anchor_missing","errorMessage":"github_attachment_canonical_anchor_missing","messagePattern":"github_attachment_canonical_anchor_missing","errorType":"error_code","errorClass":"GitHubAttachmentUnavailableError","httpStatus":null,"severity":"error","filePath":"server/src/services/chat-github-attachments.ts","lineNumber":668,"sourceCode":"    (image) =>\n      image.getAttribute(\"src\") === locator.url ||\n      sameAssetImage(image.getAttribute(\"src\")!),\n  );\n  if (candidates.length > 1 || sameAssetImages.length > 1)\n    throw new GitHubAttachmentUnavailableError(\n      \"github_attachment_canonical_mapping_ambiguous\",\n    );\n  if (candidates.length === 1 && sameAssetImages.length === 1)\n    return candidates[0]!;\n  if (\n    [...fragment.querySelectorAll(\"img[src]\")].some((image) =>\n      signedImage(image.getAttribute(\"src\")!),\n    )\n  )\n    throw new GitHubAttachmentUnavailableError(\n      \"github_attachment_canonical_image_without_source_anchor\",\n    );\n  throw new GitHubAttachmentUnavailableError(\n    \"github_attachment_canonical_anchor_missing\",\n  );\n}\n\nfunction imageSignatureMatches(body: Buffer, mime: string): boolean {\n  if (mime === \"image/png\")\n    return body\n      .subarray(0, 8)\n      .equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]));\n  if (mime === \"image/jpeg\" || mime === \"image/jpg\")\n    return body[0] === 255 && body[1] === 216 && body[2] === 255;\n  if (mime === \"image/gif\")\n    return /^(GIF87a|GIF89a)$/.test(body.subarray(0, 6).toString(\"ascii\"));\n  if (mime === \"image/webp\")\n    return (\n      body.subarray(0, 4).toString(\"ascii\") === \"RIFF\" &&\n      body.subarray(8, 12).toString(\"ascii\") === \"WEBP\"\n    );","sourceCodeStart":650,"sourceCodeEnd":686,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-github-attachments.ts#L650-L686","documentation":"GitHubAttachmentUnavailableError with code github_attachment_canonical_anchor_missing is the terminal fallback in resolveCanonicalAttachmentTargetOrThrow: after checking all anchors and images, the rendered HTML contains no anchor or img matching the locator's asset at all. The source attachment URL simply does not appear in the canonical rendering, so no signed target can be derived.","triggerScenarios":"The comment body no longer contains the attachment (image deleted/edited out), the asset was uploaded in a different comment than the one fetched, or the locator URL never appeared in this comment's rendered HTML.","commonSituations":"Stale locator after a comment edit removed the image; resolving against the wrong comment in the thread; GitHub render omitting the image (e.g. content suppressed); attachment moved to another issue/comment.","solutions":["Verify the locator points at the comment that actually contains the image; re-derive the locator from the live thread.","Re-upload or re-add the image to the comment if it was removed, then re-record the body SHA-256.","Re-fetch the comment fresh — an edit race could have served an outdated body (which would otherwise fail earlier as body mismatch)."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"function bodyMentionsAsset(body: string, assetUrl: string): boolean {\n  return body.includes(assetUrl.split('/').pop()!);\n}\nif (!bodyMentionsAsset(currentCommentBody, attachment.url)) console.warn('asset absent from this comment');","typeGuard":null,"tryCatchPattern":"try {\n  await prepareGitHubPublicAttachment(attachment, signal, resolver);\n} catch (e) {\n  if (e instanceof GitHubAttachmentUnavailableError) {\n    // resolveCanonical returns null for unavailable; surface a user-facing 'attachment no longer present' state\n    markAttachmentMissing(attachment);\n  } else throw e;\n}","preventionTips":["Verify the locator references the comment that actually embeds the image.","Invalidate locators when the comment is edited or the image removed.","Re-upload the image if it must remain resolvable.","Keep the locator's sourceBodySha256 in sync with the live comment."],"tags":["github","attachments","html-parsing","anchors"],"backgroundTag":"resource-not-found","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"}