{"record":{"id":"53544557ea089d13","repo":"different-ai/openwork","slug":"only-workspace-admins-can-remove-members","errorCode":null,"errorMessage":"Only workspace admins can remove members.","messagePattern":"Only workspace admins can remove members\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_providers/org-dashboard-provider.tsx","lineNumber":700,"sourceCode":"      ensureActiveOrganizationSelected();\n      const { response, payload } = await requestJson(\n        `/v1/members/${encodeURIComponent(memberId)}/role`,\n        {\n          method: \"POST\",\n          body: JSON.stringify({ role }),\n        },\n        12000,\n      );\n\n      if (!response.ok) {\n        throw getRequestError(payload, response, `Failed to update member (${response.status}).`);\n      }\n    });\n  }\n\n  async function removeMember(memberId: string) {\n    if (!getCurrentAccess().canRemoveMembers) {\n      throw new Error(\"Only workspace admins can remove members.\");\n    }\n    ensureTargetIsNotOwner(memberId);\n\n    await runMutation(\"remove-member\", async () => {\n      ensureActiveOrganizationSelected();\n      const { response, payload } = await requestJson(\n        `/v1/members/${encodeURIComponent(memberId)}`,\n        { method: \"DELETE\" },\n        12000,\n      );\n\n      if (response.status !== 204 && !response.ok) {\n        throw getRequestError(payload, response, `Failed to remove member (${response.status}).`);\n      }\n    });\n  }\n\n  async function transferOwnership(memberId: string) {","sourceCodeStart":682,"sourceCodeEnd":718,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_providers/org-dashboard-provider.tsx#L682-L718","documentation":"removeMember requires access.canRemoveMembers before issuing the removal request, and additionally refuses to remove the owner via ensureTargetIsNotOwner. When the current member is not a workspace admin the provider throws \"Only workspace admins can remove members.\" and no API call is made. It is the client-side authorization gate for removing org members.","triggerScenarios":"Calling removeMember(memberId) (e.g. from ManageMembersScreen's member row action) while the current member's resolved access flags lack canRemoveMembers.","commonSituations":"A non-admin member triggers the remove action via a still-visible button; the current member's role was downgraded but the UI didn't re-render; the target happens to be the owner and the caller conflates the owner-protection error with this one.","solutions":["Have a workspace admin remove the member.","Confirm your role in the active organization.","Refresh org context if your privileges changed recently, then retry.","Hide the remove action unless access.canRemoveMembers is true."],"exampleFix":"// before\n<MenuItem onClick={() => removeMember(member.id)}>Remove</MenuItem>\n\n// after\n{access.canRemoveMembers && (\n  <MenuItem onClick={() => removeMember(member.id)}>Remove</MenuItem>\n)}","handlingStrategy":"try-catch","validationCode":"if (!access.canRemoveMembers) return; // hide remove action first","typeGuard":null,"tryCatchPattern":"try {\n  await removeMember(memberId);\n} catch (e) {\n  if (e instanceof Error && /remove members|owner/.test(e.message)) {\n    toast(e.message);\n  } else throw e;\n}","preventionTips":["Render remove actions only for canRemoveMembers.","Never offer remove for the owner row (also blocked server-side).","Keep member list and access flags in sync with orgContext."],"tags":["authorization","rbac","members"],"backgroundTag":"insufficient-permissions","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}