toeverything/AFFiNE · warning · CommentNotFound
comment_not_found
comment_not_found
Error message
Comment not found.
What it means
Thrown by the updateComment GraphQL mutation when service.getComment(input.id) returns null. Category 'resource_not_found', code 'comment_not_found'. The lookup happens before permission assertion, so this fires whether or not the caller would have had access — the comment simply does not exist (or was deleted) at the time of the call.
Source
Thrown at packages/backend/server/src/core/comment/resolver.ts:111
user: {
id: me.id,
name: me.name,
avatarUrl: me.avatarUrl,
},
replies: [],
};
}
@Mutation(() => Boolean, {
description: 'Update a comment content',
})
async updateComment(
@CurrentUser() me: UserType,
@Args('input') input: CommentUpdateInput
) {
const comment = await this.service.getComment(input.id);
if (!comment) {
throw new CommentNotFound();
}
await this.assertPermission(me, comment, 'Doc.Comments.Update');
await this.service.updateComment(input);
publishCommentChanged(this.realtime, comment.workspaceId, comment.docId);
return true;
}
@Mutation(() => Boolean, {
description: 'Resolve a comment or not',
})
async resolveComment(
@CurrentUser() me: UserType,
@Args('input') input: CommentResolveInput
) {
const comment = await this.service.getComment(input.id);
if (!comment) {View on GitHub (pinned to 26c515e050)
Solutions
- Refresh the comment thread and confirm the comment still exists before retrying the edit.
- On the client, treat comment_not_found as 'this comment no longer exists' and remove it from the UI rather than showing an error.
- Ensure the client sends the correct, current comment id.
Example fix
// before
await updateComment({ id: comment.id, content });
// after
try {
await updateComment({ id: comment.id, content });
} catch (e) {
if (e.code === 'comment_not_found') {
removeCommentFromThread(comment.id);
show('This comment no longer exists.');
} else { throw e; }
} Defensive patterns
Strategy: try-catch
Validate before calling
const exists = await service.getComment(input.id);
if (!exists) { removeCommentFromThread(input.id); return; }
await updateComment(input); Type guard
function commentExists<T>(c: T | null): c is T {
return c !== null;
} Try / catch
try {
await updateComment(input);
} catch (e) {
if (e.code === 'comment_not_found') {
removeCommentFromThread(input.id);
show('This comment no longer exists.');
} else throw e;
} Prevention
- Refresh the comment thread before editing; remove deleted comments from the UI.
- Treat comment_not_found as a soft-removal, not a hard error.
- Reconcile local state with realtime comment-changed events.
When it happens
Trigger: Calling updateComment (comment/resolver.ts:109-112) with an input.id for which getComment returns null: the comment was deleted, the id is wrong, or the id belongs to a different workspace/doc.
Common situations: The user has a stale comment list open and edits a comment that was deleted in another tab/device; a wrong id passed by a client; a comment that was resolved/removed by moderation between render and edit.
Related errors
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/c310bce2f934325f.
Report an issue: GitHub.