paperclipai/paperclip · error · GitHubAttachmentUnavailableError
github_attachment_canonical_html_unavailable
github_attachment_canonical_html_unavailable
Error message
github_attachment_canonical_html_unavailable
What it means
GitHubAttachmentUnavailableError with code github_attachment_canonical_html_unavailable is thrown by resolveCanonicalAttachmentTargetOrThrow in chat-github-attachments.ts when the GitHub API comment/issue response row's body_html field is not a string or exceeds 600,000 characters. The service relies on GitHub's server-rendered HTML to locate the signed image anchor; without usable body_html it cannot safely resolve a canonical download target. This is a deliberate guard, not a network failure.
Source
Thrown at server/src/services/chat-github-attachments.ts:572
if (
String(row.id) !== locator.sourceMessageId ||
typeof row.url !== "string" ||
row.url.toLowerCase() !== request.url.toLowerCase()
)
throw new GitHubAttachmentUnavailableError(
"github_attachment_canonical_source_mismatch",
);
if (
typeof row.body !== "string" ||
row.body.length > 200_000 ||
createHash("sha256").update(row.body).digest("hex") !==
locator.sourceBodySha256
)
throw new GitHubAttachmentUnavailableError(
"github_attachment_canonical_body_mismatch",
);
if (typeof row.body_html !== "string" || row.body_html.length > 600_000)
throw new GitHubAttachmentUnavailableError(
"github_attachment_canonical_html_unavailable",
);
if (thread[4]) {
if (
row.pull_request_url !==
`https://api.github.com/repos/${thread[1]}/pulls/${thread[3]}` ||
String(row.in_reply_to_id ?? row.id) !== thread[4]
)
throw new GitHubAttachmentUnavailableError(
"github_attachment_canonical_source_mismatch",
);
} else if (
row.issue_url !==
`https://api.github.com/repos/${thread[1]}/issues/${thread[3]}`
)
throw new GitHubAttachmentUnavailableError(
"github_attachment_canonical_source_mismatch",
);View on GitHub (pinned to 01ad858492)
Solutions
- Ensure the comment resolver fetches the GitHub API row with rendered HTML included (default JSON representation returns body_html; do not pass Accept headers that strip it).
- Verify the resolver passes the raw API row object into resolveGitHubCommentAttachmentTarget, not a projection that drops body_html.
- If the comment is genuinely huge (>600KB HTML), reduce the comment content on GitHub or split the attachment into a smaller comment; the cap is intentional.
- Check fixtures/tests supply a realistic body_html string.
Example fix
// before
resolveGitHubCommentAttachmentTarget(attachment, { id: row.id, body: row.body });
// after
resolveGitHubCommentAttachmentTarget(attachment, row); // keep full API row incl. body_html Defensive patterns
Strategy: validation
Validate before calling
function hasRenderableHtml(row: unknown): boolean {
return typeof row === 'object' && row !== null && 'body_html' in row &&
typeof (row as any).body_html === 'string' && (row as any).body_html.length <= 600_000;
}
if (!hasRenderableHtml(apiRow)) throw new Error('resolver response lacks usable body_html'); Type guard
const isRowWithHtml = (v: unknown): v is { body_html: string; [k: string]: unknown } =>
typeof v === 'object' && v !== null && typeof (v as any).body_html === 'string'; Try / catch
try {
const target = resolveGitHubCommentAttachmentTarget(attachment, row);
if (target === null) skipCanonicalPath(attachment);
} catch (e) { if (e instanceof GitHubAttachmentUnavailableError) fallback(attachment); else throw e; } Prevention
- Fetch GitHub rows with the default JSON representation so body_html is present.
- Don't project/strip fields from the API row before resolving.
- Watch for comments near the 600KB HTML cap and split large comments.
- Keep test fixtures realistic, including body_html.
When it happens
Trigger: Calling resolveGitHubCommentAttachmentTarget/prepareGitHubPublicAttachment for a GitHub comment whose API response has body_html missing or null (e.g. mime_type requested as text only), or a comment whose rendered HTML exceeds the 600KB cap (very large comment bodies).
Common situations: Resolver responses built from an API client configured without 'application/vnd.github.html+json' or without full JSON rendering; extremely long issue comments with many embedded images; mocked/stubbed GitHub API fixtures that omit body_html; GitHub changing the render payload shape.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- github_attachment_canonical_file_unsupported
- github_attachment_canonical_image_count_invalid
- github_attachment_canonical_target_denied
- github_attachment_canonical_mapping_ambiguous
- github_attachment_canonical_image_without_source_anchor
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/e76d86aebdededac.
Report an issue: GitHub.