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

  1. Refresh the comment thread and confirm the comment still exists before retrying the edit.
  2. On the client, treat comment_not_found as 'this comment no longer exists' and remove it from the UI rather than showing an error.
  3. 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

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.