toeverything/AFFiNE · error · CommentNotFound
comment_not_found
comment_not_found
Error message
Comment not found.
What it means
CommentNotFound (resource_not_found / comment_not_found) thrown by CommentModel.createReply (packages/backend/server/src/models/comment.ts:285) when replying to a comment whose id does not resolve via this.get(data.commentId). The ReplyCreate schema parsed successfully, but the parent comment row is missing or not visible to the caller. Surfaced as a structured UserFriendlyError, so GraphQL/REST clients see a clean not_found.
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 26c515e050)
Solutions
- Verify the comment exists and is in scope before submitting the reply: GET /workspaces/{ws}/docs/{doc}/comments/{commentId}.
- If the comment was deleted, discard the reply draft or recreate the parent comment first.
- Catch CommentNotFound by code and surface a user-facing 'This comment no longer exists' message in the UI.
- In tests, ensure the parent comment is created in the same workspace before createReply.
Example fix
// before
await commentModel.createReply({ commentId, body });
// after
const parent = await commentModel.get(commentId);
if (!parent) throw new Error('Cannot reply: parent comment is gone.');
await commentModel.createReply({ commentId, body }); Defensive patterns
Strategy: validation
Validate before calling
const parent = await commentModel.get(commentId);
if (!parent) {
throw new Error(`Cannot reply: parent comment ${commentId} not found`);
}
await commentModel.createReply({ commentId, body }); Type guard
const commentExists = (c: Comment | null): c is Comment => c !== null;
Try / catch
try {
await commentModel.createReply(input);
} catch (e) {
if (e instanceof UserFriendlyError && e.code === 'comment_not_found') {
res.status(404).send('This comment no longer exists.');
return;
}
throw e;
} Prevention
- Verify the parent comment is visible to the caller before opening the reply composer.
- Drop reply drafts when the parent comment is reported deleted by the server.
- In tests, always seed the parent comment in the same workspace before createReply.
When it happens
Trigger: Calling createReply with a ReplyCreate payload whose commentId refers to a deleted, non-existent, or workspace-inaccessible comment. this.get() returns null (comment filtered by workspace/scope or simply absent), so the guard throws before inserting into the reply table.
Common situations: Client holds a stale commentId after the comment was deleted; reply posted to a comment in a different workspace; race where the comment is removed between UI load and reply submit; test fixture that forgot to seed the parent comment.
Related errors
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/a667b838ec7623e2.
Report an issue: GitHub.