toeverything/AFFiNE · error · OwnerCanNotLeaveWorkspace

owner_can_not_leave_workspace

owner_can_not_leave_workspace

Error message

Owner can not leave the workspace.

What it means

Thrown by `leaveWorkspace` when the caller is the workspace `Owner`. Workspaces must always retain an owner, so the owner cannot self-remove; ownership must be transferred first. Coded `owner_can_not_leave_workspace` (action_forbidden).

Source

Thrown at packages/backend/server/src/core/workspaces/resolvers/member.ts:770

      nullable: true,
      deprecationReason: 'no used anymore',
    })
    _sendLeaveMail?: boolean,
    @Args('workspaceName', {
      nullable: true,
      deprecationReason: 'no longer used',
    })
    _workspaceName?: string
  ) {
    const role = await this.models.workspaceUser.getActive(
      workspaceId,
      user.id
    );
    if (!role) {
      throw new MemberNotFoundInSpace({ spaceId: workspaceId });
    }
    if (role.type === WorkspaceRole.Owner) {
      throw new OwnerCanNotLeaveWorkspace();
    }

    await this.models.workspaceUser.delete(workspaceId, user.id);
    this.event.emit('workspace.members.leave', {
      workspaceId,
      userId: user.id,
    });

    this.event.emit('workspace.members.updated', {
      workspaceId,
    });
    await this.policy.reconcileWorkspaceQuotaState(workspaceId);

    return true;
  }

  private async acceptInvitationByEmail(role: WorkspaceUserCompat) {
    await this.assertWorkspaceAcceptsMemberChange(role.workspaceId);

View on GitHub (pinned to 26c515e050)

Solutions

  1. Transfer ownership to another admin member first via the workspace settings UI, then leave.
  2. Disable the Leave control when `role === 'Owner'` and surface a 'transfer ownership first' message.
  3. If leaving permanently, assign a new owner and only then call `leaveWorkspace`.
  4. For workspaces with no other members, add a new owner before leaving or delete the workspace instead.

Example fix

// before
await sdk.leaveWorkspace({ workspaceId });

// after
if (myRole === 'Owner') {
  notify('Transfer ownership to another member before leaving.');
  openTransferOwnershipDialog();
  return;
}
await sdk.leaveWorkspace({ workspaceId });
Defensive patterns

Strategy: validation

Validate before calling

// Block leave for owners
if (myRole === 'Owner') {
  openTransferOwnershipDialog();
  return;
}
await sdk.leaveWorkspace({ workspaceId });

Type guard

function isOwner(role) {
  return role === 'Owner';
}

Try / catch

try {
  await sdk.leaveWorkspace({ workspaceId });
} catch (e) {
  if (e.code === 'owner_can_not_leave_workspace') {
    notify('Transfer ownership to another member before leaving.');
    openTransferOwnershipDialog();
  } else throw e;
}

Prevention

When it happens

Trigger: The user whose `role.type === WorkspaceRole.Owner` calls `leaveWorkspace` on their own workspace. Common when the sole/last admin tries to leave without designating a successor.

Common situations: Founder/owner leaving the org without transferring ownership; UI does not distinguish owner from regular members in the leave action; script that bulk-leaves workspaces hits one the operator owns.

Related errors


AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12). Data as JSON: /api/errors/bde269f0ada9f6cc. Report an issue: GitHub.