toeverything/AFFiNE · error · CannotDeleteOwnAccount
cannot_delete_own_account
cannot_delete_own_account
Error message
Cannot delete own account.
What it means
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.
Source
Thrown at packages/backend/server/src/core/user/resolver.ts:383
return sessionUser(result.value);
} else {
return {
email: input.users[i].email,
error: result.reason.message,
};
}
});
}
@Mutation(() => DeleteAccount, {
description: 'Delete a user account',
})
async deleteUser(
@CurrentUser() user: CurrentUser,
@Args('id') id: string
): Promise<DeleteAccount> {
if (user.id === id) {
throw new CannotDeleteOwnAccount();
}
await this.models.user.delete(id);
return { success: true };
}
@Mutation(() => UserType, {
description: 'Update an user',
})
async updateUser(
@Args('id') id: string,
@Args('input') input: ManageUserInput
): Promise<UserType> {
const user = await this.db.user.findUnique({
where: { id },
});
if (!user) {
throw new UserNotFound();View on GitHub (pinned to 26c515e050)
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.
Example fix
// before
await deleteUser({ id: session.userId });
// after
if (targetId === session.userId) {
await deleteAccount();
} else {
await deleteUser({ id: targetId });
} Defensive patterns
Strategy: validation
Validate before calling
if (targetId === session.userId) { throw new Error('Use deleteAccount for self-deletion'); } Type guard
function isSelfDelete(targetId: string, currentUserId: string): boolean {
return targetId === currentUserId;
} Try / catch
try {
await deleteUser({ id: targetId });
} catch (e) {
if (e?.code === 'cannot_delete_own_account') { await deleteAccount(); return; }
throw e;
} Prevention
- 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.
When it happens
Trigger: An admin invokes deleteUser(id) where id === currentUser.id.
Common situations: 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.
Related errors
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/5313563918e22785.
Report an issue: GitHub.