paperclipai/paperclip · error · GitHubAttachmentUnavailableError
github_attachment_canonical_anchor_missing
github_attachment_canonical_anchor_missing
Error message
github_attachment_canonical_anchor_missing
What it means
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.
Source
Thrown at server/src/services/chat-github-attachments.ts:668
(image) =>
image.getAttribute("src") === locator.url ||
sameAssetImage(image.getAttribute("src")!),
);
if (candidates.length > 1 || sameAssetImages.length > 1)
throw new GitHubAttachmentUnavailableError(
"github_attachment_canonical_mapping_ambiguous",
);
if (candidates.length === 1 && sameAssetImages.length === 1)
return candidates[0]!;
if (
[...fragment.querySelectorAll("img[src]")].some((image) =>
signedImage(image.getAttribute("src")!),
)
)
throw new GitHubAttachmentUnavailableError(
"github_attachment_canonical_image_without_source_anchor",
);
throw new GitHubAttachmentUnavailableError(
"github_attachment_canonical_anchor_missing",
);
}
function imageSignatureMatches(body: Buffer, mime: string): boolean {
if (mime === "image/png")
return body
.subarray(0, 8)
.equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]));
if (mime === "image/jpeg" || mime === "image/jpg")
return body[0] === 255 && body[1] === 216 && body[2] === 255;
if (mime === "image/gif")
return /^(GIF87a|GIF89a)$/.test(body.subarray(0, 6).toString("ascii"));
if (mime === "image/webp")
return (
body.subarray(0, 4).toString("ascii") === "RIFF" &&
body.subarray(8, 12).toString("ascii") === "WEBP"
);View on GitHub (pinned to 01ad858492)
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).
Defensive patterns
Strategy: fallback
Validate before calling
function bodyMentionsAsset(body: string, assetUrl: string): boolean {
return body.includes(assetUrl.split('/').pop()!);
}
if (!bodyMentionsAsset(currentCommentBody, attachment.url)) console.warn('asset absent from this comment'); Try / catch
try {
await prepareGitHubPublicAttachment(attachment, signal, resolver);
} catch (e) {
if (e instanceof GitHubAttachmentUnavailableError) {
// resolveCanonical returns null for unavailable; surface a user-facing 'attachment no longer present' state
markAttachmentMissing(attachment);
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- github_attachment_canonical_image_without_source_anchor
- github_attachment_canonical_image_count_invalid
- github_attachment_canonical_html_unavailable
- github_attachment_canonical_file_unsupported
- github_attachment_canonical_target_denied
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/c2150e01c02bccf8.
Report an issue: GitHub.