toeverything/AFFiNE · error · CommentAttachmentNotFound
comment_attachment_not_found
comment_attachment_not_found
Error message
Comment attachment not found.
What it means
Thrown by the comment-attachment route (GET /:id/docs/:docId/comment-attachments/:key) when commentAttachmentStorage.get(workspaceId, docId, key, true) returns neither a body nor a redirectUrl, after the Doc.Read assert passed. Plain storage-layer miss for comment media.
Solutions
- Verify the key against the comment's stored attachment data before fetching
- Re-upload the attachment and update the comment if the media matters
- Audit comment-attachment storage config if objects vanish systematically
- Render a placeholder in the UI on 404 rather than erroring the whole comment thread
Defensive patterns
Strategy: try-catch
Type guard
function isCommentAttachmentNotFound(e: unknown): e is { code: 'comment_attachment_not_found' } {
return typeof e === 'object' && e !== null && (e as any).code === 'comment_attachment_not_found';
} Try / catch
try {
return await fetchCommentAttachment(wsId, docId, key);
} catch (e) {
if (isCommentAttachmentNotFound(e)) {
return renderAttachmentPlaceholder(); // keep the comment thread usable
}
throw e;
} Prevention
- Only reference attachment keys the upload flow confirmed
- On attachment deletion, update the owning comment's payload
- Verify comment-attachment storage config after migrations
- Design comment UI to degrade gracefully per-attachment
When it happens
Trigger: Fetching a comment attachment whose key was never uploaded, was removed, or whose object is gone from the storage backend with no signed-url fallback available.
Common situations: Comments referencing deleted attachments; storage migration losing objects; wrong key passed by the client; uploads that failed before the object write but after the comment was created.
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
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/6ab3b0dfaf620823.
Report an issue: GitHub.
Appendix: source
Thrown at packages/backend/server/src/core/workspaces/controller.ts:393
@CallMetric('controllers', 'workspace_get_comment_attachment')
async commentAttachment(
@CurrentUser() user: CurrentUser,
@Param('id') workspaceId: string,
@Param('docId') docId: string,
@Param('key') key: string,
@Res() res: Response
) {
await this.ac.user(user.id).doc(workspaceId, docId).assert('Doc.Read');
const { body, metadata, redirectUrl } =
await this.commentAttachmentStorage.get(workspaceId, docId, key, true);
if (redirectUrl) {
return res.redirect(redirectUrl);
}
if (!body) {
throw new CommentAttachmentNotFound();
}
// metadata should always exists if body is not null
if (metadata) {
res.setHeader('content-type', metadata.contentType);
res.setHeader('last-modified', metadata.lastModified.toUTCString());
res.setHeader('content-length', metadata.contentLength);
} else {
this.logger.warn(
`Comment attachment ${workspaceId}/${docId}/${key} has no metadata`
);
}
applyAttachHeaders(res, {
contentType: metadata?.contentType,
filename: key,
});
res.setHeader('cache-control', 'private, max-age=2592000, immutable');View on GitHub (pinned to b4c8548c09)