paperclipai/paperclip · error · GitHubAttachmentUnavailableError
github_attachment_canonical_mapping_ambiguous
github_attachment_canonical_mapping_ambiguous
Error message
github_attachment_canonical_mapping_ambiguous
What it means
GitHubAttachmentUnavailableError with code github_attachment_canonical_mapping_ambiguous is thrown when the rendered HTML yields more than one candidate anchor target or more than one img referencing the same asset. A unique 1:1 mapping between the source anchor and the signed image is required; any duplication means the resolver cannot silently pick a target.
Source
Thrown at server/src/services/chat-github-attachments.ts:655
// The second form was observed in the exact App-rendered live comment.
// Both the original-anchor and signed-anchor forms enter one candidate set
// so duplicated or mixed renderings cannot silently choose a target.
if (
!target ||
(href !== locator.url && (href !== src || !signedImage(href)))
)
throw new GitHubAttachmentUnavailableError(
"github_attachment_canonical_target_denied",
);
candidates.push(target);
}
const sameAssetImages = [...fragment.querySelectorAll("img[src]")].filter(
(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 {View on GitHub (pinned to 01ad858492)
Solutions
- Edit the GitHub comment to reference the asset image exactly once, then re-resolve (body must still match the recorded SHA-256, so re-record the locator hash after editing).
- Remove quoted/duplicated blocks containing the same image from the comment.
- If your system stores the locator, update sourceBodySha256 after any intentional comment edit before resolving.
Example fix
// before (same image twice)  ... >  // after 
Defensive patterns
Strategy: validation
Validate before calling
function assetMentionedOnce(body: string, assetUrl: string): boolean {
const id = assetUrl.split('/').pop();
return (body.match(new RegExp(id!, 'g')) || []).length === 1;
}
if (!assetMentionedOnce(commentBody, attachment.url)) console.warn('duplicate asset reference; resolution will be ambiguous'); Try / catch
try {
const attachment = await prepareGitHubPublicAttachment(att, signal, resolver);
} catch (e) {
if (e instanceof GitHubAttachmentUnavailableError && e.code === 'github_attachment_canonical_mapping_ambiguous') {
await requireCommentCleanup(issue); // ask author to deduplicate the image
} else throw e;
} Prevention
- Reference each uploaded asset exactly once per comment.
- Avoid quote-replies that re-embed the same image.
- After comment edits, re-record the locator's body SHA-256.
- Strip duplicated images from changelog/quote blocks before upload.
When it happens
Trigger: The comment body references the same asset URL twice (duplicate markdown image, image repeated inside two anchors), so candidates.length > 1 or sameAssetImages.length > 1 after HTML parsing.
Common situations: Users pasting the same image twice in one comment; quote-reply blocks that re-embed the original image; comment edits that left a duplicated image behind; diffs/changelogs reusing the same screenshot URL.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- github_attachment_canonical_file_unsupported
- github_attachment_canonical_image_count_invalid
- github_attachment_canonical_html_unavailable
- github_attachment_canonical_target_denied
- github_attachment_canonical_image_without_source_anchor
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/1a7c29ef83055e62.
Report an issue: GitHub.