Tencent/WeKnora · info
tenant is already an admin
Error message
tenant is already an admin
What it means
ErrAlreadyAdmin is a sentinel returned by RequestRoleUpgrade when the tenant's current role is already OrgRoleAdmin. Admins cannot request an upgrade because no higher role exists; this is a fast-fail before the role-comparison check.
Source
Thrown at internal/application/service/organization.go:625
return org.OwnerTenantID == tenantID
}
// generateInviteCode generates a random 16-character invite code
func generateInviteCode() string {
bytes := make([]byte, 8)
_, _ = rand.Read(bytes)
return hex.EncodeToString(bytes)
}
// ----------------
// Join Requests
// ----------------
var (
ErrPendingRequestExists = errors.New("pending request already exists")
ErrJoinRequestNotFound = errors.New("join request not found")
ErrCannotUpgradeToSameRole = errors.New("cannot request upgrade to same or lower role")
ErrAlreadyAdmin = errors.New("tenant is already an admin")
)
// SubmitJoinRequest submits a request for the caller's tenant to join an organization.
// Dedup is now per-tenant: any user from a tenant already with a pending join
// request is rejected (the same tenant can't queue two simultaneous joins).
func (s *organizationService) SubmitJoinRequest(ctx context.Context, orgID string, userID string, tenantID uint64, message string, requestedRole types.OrgMemberRole) (*types.OrganizationJoinRequest, error) {
logger.Infof(ctx, "Tenant %d (rep user %s) submitting join request for organization %s", tenantID, userID, orgID)
existing, err := s.orgRepo.GetPendingRequestByTenantAndType(ctx, orgID, tenantID, types.JoinRequestTypeJoin)
if err == nil && existing != nil {
return nil, ErrPendingRequestExists
}
org, err := s.orgRepo.GetByID(ctx, orgID)
if err != nil {
if errors.Is(err, repository.ErrOrganizationNotFound) {
return nil, ErrOrgNotFound
}View on GitHub (pinned to 988cbb0330)
Solutions
- Do not call RequestRoleUpgrade for tenants already at OrgRoleAdmin; refresh the member's role first.
- Treat errors.Is(err, ErrAlreadyAdmin) as an idempotent success in retry flows.
- Filter admin members out of any UI list offering role upgrades.
Example fix
// before
svc.RequestRoleUpgrade(ctx, orgID, userID, tenantID, types.OrgRoleAdmin)
// after
if member.Role != types.OrgRoleAdmin {
svc.RequestRoleUpgrade(ctx, orgID, userID, tenantID, types.OrgRoleAdmin)
} Defensive patterns
Strategy: validation
Validate before calling
if member.Role == types.OrgRoleAdmin {
return nil // already admin; skip upgrade request
} Type guard
func isAdmin(m *types.OrgMember) bool { return m != nil && m.Role == types.OrgRoleAdmin } Try / catch
if errors.Is(err, organization.ErrAlreadyAdmin) {
return nil // idempotent success
} Prevention
- Refresh the member's role after any approved upgrade before retrying.
- Filter admin tenants out of upgrade-eligible lists.
- Treat ErrAlreadyAdmin as success in retry flows.
When it happens
Trigger: Calling RequestRoleUpgrade for a tenant whose org membership role is already types.OrgRoleAdmin.
Common situations: Stale client state after a previous upgrade was approved, admins re-clicking an upgrade button, or tenants listed in an upgrade queue that was not refreshed post-approval.
Related errors
- pending request already exists
- cannot request upgrade to same or lower role
- request has already been reviewed
- member_limit must be >= 0
- join request not found
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/3e81139a24630785.
Report an issue: GitHub.