toeverything/AFFiNE · error · CommentNotFound

comment_not_found

comment_not_found

Error message

Comment not found.

What it means

Thrown by CommentModel.createReply when this.get(data.commentId) returns null — the comment being replied to does not exist (deleted or unknown id). Replies are anchored to their parent comment's workspaceId/docId, which is why the parent must resolve first.

Solutions

  1. Refresh the comment list for the doc and reply to an existing comment id from that fresh list.
  2. If the parent comment was deleted, start a new comment instead of a reply.
  3. For API callers, validate the commentId exists (GET the comment) before posting the reply.
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the parent comment still exists before posting the reply
const comment = await gql.request(GET_COMMENT, { id: commentId });
if (!comment.comment) {
  refreshCommentList(); // parent is gone — reload instead of replying
} else {
  await gql.request(CREATE_REPLY, { input: { commentId, body } });
}

Type guard

const isCommentNotFound = (e: unknown): boolean =>
  getGraphqlErrorCode(e) === 'comment_not_found';

Try / catch

try {
  await createReply({ commentId, body });
} catch (e) {
  if (isCommentNotFound(e)) {
    refreshCommentList(); // drop the stale reply box
  }
}

Prevention

When it happens

Trigger: Calling the createReply mutation/API with a commentId that was deleted, a doc comment that disappeared when its page was removed, or a malformed id.

Common situations: Replying from a stale open editor after another user deleted the comment; page deleted or moved to trash taking its comments along; id typo from API consumers.

Related errors


AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18). Data as JSON: /api/errors/a667b838ec7623e2. Report an issue: GitHub.

Appendix: source

Thrown at packages/backend/server/src/models/comment.ts:285

    return changes;
  }

  // #endregion

  // #region Reply

  /**
   * Reply to a comment
   * @param input - The reply create input
   * @returns The created reply
   */
  async createReply(input: ReplyCreate) {
    const data = ReplyCreateSchema.parse(input);
    // find comment
    const comment = await this.get(data.commentId);
    if (!comment) {
      throw new CommentNotFound();
    }

    return (await this.db.reply.create({
      data: {
        ...data,
        workspaceId: comment.workspaceId,
        docId: comment.docId,
      },
    })) as Reply;
  }

  async getReply(id: string) {
    return (await this.db.reply.findUnique({
      where: { id, deletedAt: null },
    })) as Reply | null;
  }

  async listReplies(workspaceId: string, docId: string, commentId: string) {

View on GitHub (pinned to b4c8548c09)