different-ai/openwork · error
Ownership can only be transferred to an active super-admin.
Error message
Ownership can only be transferred to an active super-admin.
What it means
After the owner check, transferOwnership validates the target member: the member must exist in orgContext.members, have a joinedAt timestamp (active member), and resolve to a super-admin role via getOrgAccessFlags. If any of these fail, the provider throws "Ownership can only be transferred to an active super-admin." This enforces that ownership only passes to an active super-admin, never to a pending invite, non-member, or lower role.
Source
Thrown at ee/apps/den-web/app/(den)/dashboard/_providers/org-dashboard-provider.tsx:725
`/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}).`);
}
});
}
async function createRole(input: { roleName: string; permission: Record<string, string[]> }) {
if (!getCurrentAccess().canManageRoles) {View on GitHub (pinned to 2b7df46e8a)
Solutions
- Promote the target to super-admin first, then transfer ownership.
- Only transfer to a member who has accepted their invite (joinedAt set).
- Re-check the member list and use a fresh memberId if the target recently joined or left.
- Filter the transfer UI to active super-admins only.
Example fix
// before
handleTransferOwnership(inviteeId); // pending invite
// after
const target = members.find((m) => m.id === inviteeId);
const ok = target?.joinedAt && getOrgAccessFlags(target.role, target.isOwner, roles).isSuperAdmin;
if (!ok) {
showError("Ownership can only be transferred to an active super-admin.");
return;
}
handleTransferOwnership(inviteeId); Defensive patterns
Strategy: validation
Validate before calling
const target = members.find((m) => m.id === memberId);
const eligible = !!target?.joinedAt && getOrgAccessFlags(target.role, target.isOwner, roles).isSuperAdmin;
if (!eligible) { /* block call: promote to super-admin first */ } Type guard
function isEligibleOwnerTarget(m: Member | undefined, roles: OrgRole[]): m is Member & { joinedAt: string } {
return !!m && !!m.joinedAt && !m.isOwner && getOrgAccessFlags(m.role, m.isOwner, roles).isSuperAdmin;
} Try / catch
try {
await transferOwnership(memberId);
} catch (e) {
if (e instanceof Error && e.message.includes("active super-admin")) {
showNotice("Promote the member to super-admin before transferring ownership.");
} else throw e;
} Prevention
- Only list active super-admins in the transfer-target picker.
- Exclude pending invitations (no joinedAt) from targets.
- Grant super-admin first, then transfer ownership in two steps.
When it happens
Trigger: Calling transferOwnership with a memberId that is not in the member list, belongs to a member who has not joined (no joinedAt), or whose role is not a super-admin (e.g. member/admin/custom role).
Common situations: Selecting a pending invitation as the transfer target; attempting to promote a regular member directly to owner in one step (must first grant super-admin); memberId from a stale member list after the target left the org; passing a wrong/typo'd id programmatically.
Related errors
- The owner role cannot be assigned from this action.
- Only the workspace owner can transfer ownership.
- Agent context diagnostics timeout must be between 1 ms and 3
- Invalid cloud provider sync response.
- Invalid cloud provider sync status.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/cb44516cb693dbf1.
Report an issue: GitHub.