{"record":{"id":"5313563918e22785","repo":"toeverything/AFFiNE","slug":"cannot-delete-own-account","errorCode":"cannot_delete_own_account","errorMessage":"Cannot delete own account.","messagePattern":"Cannot delete own account\\.","errorType":"exception","errorClass":"CannotDeleteOwnAccount","httpStatus":403,"severity":"error","filePath":"packages/backend/server/src/core/user/resolver.ts","lineNumber":383,"sourceCode":"        return sessionUser(result.value);\n      } else {\n        return {\n          email: input.users[i].email,\n          error: result.reason.message,\n        };\n      }\n    });\n  }\n\n  @Mutation(() => DeleteAccount, {\n    description: 'Delete a user account',\n  })\n  async deleteUser(\n    @CurrentUser() user: CurrentUser,\n    @Args('id') id: string\n  ): Promise<DeleteAccount> {\n    if (user.id === id) {\n      throw new CannotDeleteOwnAccount();\n    }\n    await this.models.user.delete(id);\n    return { success: true };\n  }\n\n  @Mutation(() => UserType, {\n    description: 'Update an user',\n  })\n  async updateUser(\n    @Args('id') id: string,\n    @Args('input') input: ManageUserInput\n  ): Promise<UserType> {\n    const user = await this.db.user.findUnique({\n      where: { id },\n    });\n\n    if (!user) {\n      throw new UserNotFound();","sourceCodeStart":365,"sourceCodeEnd":401,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/core/user/resolver.ts#L365-L401","documentation":"Thrown by the admin deleteUser mutation when the target id equals the authenticated user's own id. The admin user-deletion path is for managing other accounts; self-deletion must go through deleteAccount instead. This guard prevents an admin from locking themselves out by deleting their own account through the admin endpoint.","triggerScenarios":"An admin invokes deleteUser(id) where id === currentUser.id.","commonSituations":"Admin UI prefilled with the current user's id; admin attempting self-cleanup via the wrong mutation; client routing self-delete to the admin mutation by mistake.","solutions":["Use the deleteAccount mutation (not deleteUser) to delete your own account.","In the admin UI, hide/disable the delete action for the currently logged-in admin's row.","Guard the client call: skip deleteUser when targetId === session.userId."],"exampleFix":"// before\nawait deleteUser({ id: session.userId });\n\n// after\nif (targetId === session.userId) {\n  await deleteAccount();\n} else {\n  await deleteUser({ id: targetId });\n}","handlingStrategy":"validation","validationCode":"if (targetId === session.userId) { throw new Error('Use deleteAccount for self-deletion'); }","typeGuard":"function isSelfDelete(targetId: string, currentUserId: string): boolean {\n  return targetId === currentUserId;\n}","tryCatchPattern":"try {\n  await deleteUser({ id: targetId });\n} catch (e) {\n  if (e?.code === 'cannot_delete_own_account') { await deleteAccount(); return; }\n  throw e;\n}","preventionTips":["Route self-deletion through deleteAccount, not deleteUser.","Disable the delete action for the current admin row in the UI.","Guard client calls with a targetId === session.userId check."],"tags":["user","admin","graphql","authorization"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}