different-ai/openwork · error

Only workspace admins can remove members.

Error message

Only workspace admins can remove members.

What it means

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.

Source

Thrown at ee/apps/den-web/app/(den)/dashboard/_providers/org-dashboard-provider.tsx:700

      ensureActiveOrganizationSelected();
      const { response, payload } = await requestJson(
        `/v1/members/${encodeURIComponent(memberId)}/role`,
        {
          method: "POST",
          body: JSON.stringify({ role }),
        },
        12000,
      );

      if (!response.ok) {
        throw getRequestError(payload, response, `Failed to update member (${response.status}).`);
      }
    });
  }

  async function removeMember(memberId: string) {
    if (!getCurrentAccess().canRemoveMembers) {
      throw new Error("Only workspace admins can remove members.");
    }
    ensureTargetIsNotOwner(memberId);

    await runMutation("remove-member", async () => {
      ensureActiveOrganizationSelected();
      const { response, payload } = await requestJson(
        `/v1/members/${encodeURIComponent(memberId)}`,
        { method: "DELETE" },
        12000,
      );

      if (response.status !== 204 && !response.ok) {
        throw getRequestError(payload, response, `Failed to remove member (${response.status}).`);
      }
    });
  }

  async function transferOwnership(memberId: string) {

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Have a workspace admin remove the member.
  2. Confirm your role in the active organization.
  3. Refresh org context if your privileges changed recently, then retry.
  4. Hide the remove action unless access.canRemoveMembers is true.

Example fix

// before
<MenuItem onClick={() => removeMember(member.id)}>Remove</MenuItem>

// after
{access.canRemoveMembers && (
  <MenuItem onClick={() => removeMember(member.id)}>Remove</MenuItem>
)}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!access.canRemoveMembers) return; // hide remove action first

Try / catch

try {
  await removeMember(memberId);
} catch (e) {
  if (e instanceof Error && /remove members|owner/.test(e.message)) {
    toast(e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling removeMember(memberId) (e.g. from ManageMembersScreen's member row action) while the current member's resolved access flags lack canRemoveMembers.

Common situations: 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.

Understand the failure class

Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/53544557ea089d13. Report an issue: GitHub.