different-ai/openwork · error

Only the workspace owner can transfer ownership.

Error message

Only the workspace owner can transfer ownership.

What it means

transferOwnership is restricted to the current organization owner via access.canTransferOwnership. Any other member (including super-admins who are not the owner) throws "Only the workspace owner can transfer ownership." before target validation. Ownership transfer is a single-owner action by design.

Source

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

    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) {
    if (!getCurrentAccess().canTransferOwnership) {
      throw new Error("Only the workspace owner can transfer ownership.");
    }
    const target = ensureTargetIsNotOwner(memberId);
    const targetAccess = getOrgAccessFlags(target?.role ?? "member", target?.isOwner ?? false, orgContext?.roles);
    if (!target || !target.joinedAt || !targetAccess.isSuperAdmin) {
      throw new Error("Ownership can only be transferred to an active super-admin.");
    }

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

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

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Have the current organization owner perform the transfer.
  2. Verify who the owner is on the Members screen (owner flag) before attempting.
  3. Refresh org context if ownership was recently transferred.
  4. Show the transfer control only to members whose access flags include canTransferOwnership.

Example fix

// before
<Button onClick={() => handleTransferOwnership(member.id)}>Make owner</Button>

// after
{access.canTransferOwnership && (
  <Button onClick={() => handleTransferOwnership(member.id)}>Make owner</Button>
)}
Defensive patterns

Strategy: validation

Validate before calling

if (!access.canTransferOwnership) return; // only the owner sees transfer controls

Try / catch

try {
  await transferOwnership(memberId);
} catch (e) {
  if (e instanceof Error && /transfer ownership|super-admin/.test(e.message)) {
    toast(e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling transferOwnership(memberId) (e.g. from handleTransferOwnership) when the signed-in member is a super-admin or admin but not the organization owner, so canTransferOwnership is false.

Common situations: A super-admin assumes they can hand off ownership; an admin tries to resolve an owner leaving the team; the previous owner was already transferred and orgContext still lists the caller as owner.

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/23e8f894a3b1602c. Report an issue: GitHub.