{"record":{"id":"5bcfdf435f493b56","repo":"toeverything/AFFiNE","slug":"can-not-revoke-yourself","errorCode":"can_not_revoke_yourself","errorMessage":"You can not revoke your own permission.","messagePattern":"You can not revoke your own permission\\.","errorType":"http","errorClass":"CanNotRevokeYourself","httpStatus":403,"severity":"error","filePath":"packages/backend/server/src/core/workspaces/resolvers/member.ts","lineNumber":646,"sourceCode":"        inviteeId\n      );\n      status = invitation?.status;\n    } else {\n      const invitation = await this.models.workspaceUser.getById(inviteId);\n      status = invitation?.status;\n    }\n\n    return { workspace, user: owner, invitee, status };\n  }\n\n  @Mutation(() => Boolean)\n  async revokeMember(\n    @CurrentUser() me: CurrentUser,\n    @Args('workspaceId') workspaceId: string,\n    @Args('userId') userId: string\n  ) {\n    if (userId === me.id) {\n      throw new CanNotRevokeYourself();\n    }\n\n    const role = await this.models.workspaceUser.get(workspaceId, userId);\n\n    if (!role) {\n      throw new MemberNotFoundInSpace({ spaceId: workspaceId });\n    }\n\n    await this.ac\n      .user(me.id)\n      .workspace(workspaceId)\n      .assert(\n        role.type === WorkspaceRole.Admin\n          ? 'Workspace.Administrators.Manage'\n          : 'Workspace.Users.Manage'\n      );\n\n    await this.models.workspaceUser.delete(workspaceId, userId);","sourceCodeStart":628,"sourceCodeEnd":664,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/core/workspaces/resolvers/member.ts#L628-L664","documentation":"Thrown by the `revokeMember` mutation when the target `userId` equals the caller's own id (`me.id`). The workspace service forbids self-revocation as a safety guard so an admin cannot accidentally strip their own access. Categorised under `can_not_revoke_yourself` (action_forbidden).","triggerScenarios":"Invoking `revokeMember(workspaceId, userId)` with `userId` set to the currently authenticated user's id — e.g., a UI that prefills the current user into the target field, or a script iterating over all member ids including the operator's own.","commonSituations":"A 'remove member' dropdown that accidentally lists the current user; bulk-remove tooling that iterates member ids without filtering out the caller; frontend bug passing `me.id` instead of the selected row's id.","solutions":["Filter the current user out of the removable-members list in the UI before showing it.","In bulk operations, skip entries where `userId === me.id` and log them instead of calling `revokeMember`.","If you actually need to leave the workspace, call `leaveWorkspace` instead.","Add a client-side guard: `if (userId === me.id) return;` before dispatching the mutation."],"exampleFix":"// before\nawait sdk.revokeMember({ workspaceId, userId: selectedUserId });\n\n// after\nif (selectedUserId === me.id) {\n  toast.error('You cannot revoke your own access. Use Leave Workspace instead.');\n  return;\n}\nawait sdk.revokeMember({ workspaceId, userId: selectedUserId });","handlingStrategy":"validation","validationCode":"// Guard before dispatching the mutation\nfunction canRevoke(meId, targetId) {\n  return meId !== targetId;\n}\nif (!canRevoke(me.id, userId)) {\n  notify('Use Leave Workspace to remove yourself.');\n  return;\n}","typeGuard":"function isSelfRevoke(meId, targetId) {\n  return meId === targetId;\n}","tryCatchPattern":"try {\n  await sdk.revokeMember({ workspaceId, userId });\n} catch (e) {\n  if (e.code === 'can_not_revoke_yourself') {\n    notify('You cannot revoke your own access. Use Leave Workspace.');\n  } else throw e;\n}","preventionTips":["Exclude the current user from the removable-members list in the UI.","In bulk flows, filter out entries where userId === operator id.","Direct self-removal at `leaveWorkspace` instead."],"tags":["graphql","workspace","members","authorization","nestjs"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}