weaviate/weaviate · error · ErrBadRequest
%w: roles already exist
Error message
%w: roles already exist
What it means
The RAFT-applied RBAC create/upsert command was rejected because one of the requested role names conflicts with an existing role. The Manager scans ALL existing roles — not just exact names — via namespacing.FindShortNameConflict, so a short name that collides across namespaces also triggers this. This is the authoritative guard at apply time because the handler's earlier pre-check read is not atomic with the write.
Source
Thrown at cluster/rbac/manager.go:179
}
req := &cmd.CreateRolesRequest{}
if err := json.Unmarshal(c.SubCommand, req); err != nil {
return fmt.Errorf("%w: %w", ErrBadRequest, err)
}
// Scan all roles, not just the exact names, to enforce short-name
// uniqueness across namespaces. The handler's pre-check read is not atomic
// with this write; applies run serially, so this is the authoritative guard.
if req.RoleCreation {
allRoles, err := m.authZ.GetRoles()
if err != nil {
return err
}
existing := maps.Keys(allRoles)
for name := range req.Roles {
if namespacing.FindShortNameConflict(existing, name) != namespacing.NoRoleConflict {
return fmt.Errorf("%w: roles already exist", ErrBadRequest)
}
}
}
if req.Version < cmd.RBACLatestCommandPolicyVersion {
for roleName, policies := range req.Roles {
permissions := []*authorization.Policy{}
for _, p := range policies {
permissions = append(permissions, &p)
}
// remove old permissions
if err := m.authZ.RemovePermissions(roleName, permissions); err != nil {
return err
}
}
}
reqMigrated, err := migrateUpsertRolesPermissions(req)View on GitHub (pinned to 75aa4b6d11)
Solutions
- Check whether the role already exists (GET roles) before creating, and skip or turn the create into an update of permissions
- Pick a role name whose short name is unique across all namespaces (namespacing enforces short-name uniqueness, not just exact match)
- Make create calls idempotent: on this error treat the role as existing and continue instead of retrying the create
- If a partial multi-role request failed, remove the conflicting role names and resubmit only the new ones
Example fix
// before
client.Roles().Creator().WithRole(&schema.Role{Name: "viewer", Permissions: perms}).Do(ctx) // fails: roles already exist
// after
existing, _ := client.Roles().AllGetter().Do(ctx)
if _, ok := existing["viewer"]; !ok {
client.Roles().Creator().WithRole(&schema.Role{Name: "viewer", Permissions: perms}).Do(ctx)
} Defensive patterns
Strategy: validation
Validate before calling
roles, err := client.Roles().AllGetter().Do(ctx)
if err != nil { return err }
if _, exists := roles["viewer"]; exists {
// skip create or update permissions instead
} Type guard
func roleExists(roles map[string]schema.Role, name string) bool {
_, ok := roles[name]
return ok
} Try / catch
if err := client.Roles().Creator().WithRole(r).Do(ctx); err != nil && strings.Contains(err.Error(), "roles already exist") {
// treat as existing, continue
} Prevention
- List existing roles before any create and make creation idempotent
- Keep role short names globally unique, avoiding namespace-prefix collisions
- Serialize role-management changes through one operator/process to avoid races
When it happens
Trigger: Calling the create-roles RBAC API (applied as UpsertRolesPermissions with req.RoleCreation=true) when the role name already exists, or when its namespace-qualified short name conflicts with another existing role. Also hit by concurrent or retried create attempts after a first successful apply.
Common situations: Retry logic re-sending a role-creation request that already succeeded; two clients creating the same role concurrently; role names differing only by namespace prefix so their short names collide; migrations that re-create existing roles.
Related errors
- ErrTaskConflict
- ErrBadRequest
- namespace already exists
- one or more of the roles you want to assign is empty
- roles can not be empty
AI-assisted analysis of weaviate/weaviate@75aa4b6d11 (2026-09-04).
Data as JSON: /api/errors/6272dd9d647b3c30.
Report an issue: GitHub.