{"record":{"id":"c310bce2f934325f","repo":"toeverything/AFFiNE","slug":"comment-not-found","errorCode":"comment_not_found","errorMessage":"Comment not found.","messagePattern":"Comment not found\\.","errorType":"exception","errorClass":"CommentNotFound","httpStatus":404,"severity":"warning","filePath":"packages/backend/server/src/core/comment/resolver.ts","lineNumber":111,"sourceCode":"      user: {\n        id: me.id,\n        name: me.name,\n        avatarUrl: me.avatarUrl,\n      },\n      replies: [],\n    };\n  }\n\n  @Mutation(() => Boolean, {\n    description: 'Update a comment content',\n  })\n  async updateComment(\n    @CurrentUser() me: UserType,\n    @Args('input') input: CommentUpdateInput\n  ) {\n    const comment = await this.service.getComment(input.id);\n    if (!comment) {\n      throw new CommentNotFound();\n    }\n\n    await this.assertPermission(me, comment, 'Doc.Comments.Update');\n\n    await this.service.updateComment(input);\n    publishCommentChanged(this.realtime, comment.workspaceId, comment.docId);\n    return true;\n  }\n\n  @Mutation(() => Boolean, {\n    description: 'Resolve a comment or not',\n  })\n  async resolveComment(\n    @CurrentUser() me: UserType,\n    @Args('input') input: CommentResolveInput\n  ) {\n    const comment = await this.service.getComment(input.id);\n    if (!comment) {","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/core/comment/resolver.ts#L93-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait updateComment({ id: comment.id, content });\n\n// after\ntry {\n  await updateComment({ id: comment.id, content });\n} catch (e) {\n  if (e.code === 'comment_not_found') {\n    removeCommentFromThread(comment.id);\n    show('This comment no longer exists.');\n  } else { throw e; }\n}","handlingStrategy":"try-catch","validationCode":"const exists = await service.getComment(input.id);\nif (!exists) { removeCommentFromThread(input.id); return; }\nawait updateComment(input);","typeGuard":"function commentExists<T>(c: T | null): c is T {\n  return c !== null;\n}","tryCatchPattern":"try {\n  await updateComment(input);\n} catch (e) {\n  if (e.code === 'comment_not_found') {\n    removeCommentFromThread(input.id);\n    show('This comment no longer exists.');\n  } else throw e;\n}","preventionTips":["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."],"tags":["comment","not-found","graphql","stale-state"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}