different-ai/openwork · error

Only workspace owners and super-admins can change member rol

Error message

Only workspace owners and super-admins can change member roles.

What it means

updateMemberRole is gated by access.canManageRoles, which only owners and super-admins satisfy. Changing a member's role when this flag is false throws "Only workspace owners and super-admins can change member roles." before ensureTargetIsNotOwner and the API call. This is a deliberate client-side RBAC check for role management.

Source

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

    }

    await runMutation("cancel-invitation", async () => {
      ensureActiveOrganizationSelected();
      const { response, payload } = await requestJson(
        `/v1/invitations/${encodeURIComponent(invitationId)}/cancel`,
        { method: "POST", body: JSON.stringify({}) },
        12000,
      );

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

  async function updateMemberRole(memberId: string, role: string) {
    if (!getCurrentAccess().canManageRoles) {
      throw new Error("Only workspace owners and super-admins can change member roles.");
    }
    ensureTargetIsNotOwner(memberId);
    ensureRoleCanBeAssigned(role);

    await runMutation("update-member-role", async () => {
      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}).`);
      }

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Ask an owner or super-admin to change the member's role.
  2. Verify your own role — only owner/super-admin roles carry canManageRoles.
  3. Refresh org context if your role was recently upgraded, then retry.
  4. Disable the role selector unless access.canManageRoles is true.

Example fix

// before
<select onChange={(e) => updateMemberRole(member.id, e.target.value)}>

// after
<select
  disabled={!access.canManageRoles}
  onChange={(e) => updateMemberRole(member.id, e.target.value)}
>
Defensive patterns

Strategy: validation

Validate before calling

if (!access.canManageRoles) {
  // disable role selector / block updateMemberRole call
}

Try / catch

try {
  await updateMemberRole(memberId, role);
} catch (e) {
  if (e instanceof Error && e.message.includes("change member roles")) {
    toast(e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling updateMemberRole(memberId, role) (e.g. from editMemberForm in ManageMembersScreen) as an admin-but-not-owner/super-admin, or any member without canManageRoles.

Common situations: A plain admin attempts to promote a member to super-admin; the role select in the member row is enabled for users who shouldn't see it; access flags are stale after the current member's role changed.

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/4b1e1c67c38d8f8f. Report an issue: GitHub.