weaviate/weaviate · warning

roles can not be empty

Error message

roles can not be empty

What it means

A 400 Bad Request returned when the assign-roles request body contains an empty Roles array (len == 0). The handler checks this after namespace/user-type validation but before authorization and role resolution. Assigning zero roles is considered a malformed request rather than a no-op.

Source

Thrown at adapters/handlers/rest/authz/handlers_authz.go:812

		if strings.TrimSpace(role) == "" {
			return authz.NewAssignRoleToUserBadRequest().WithPayload(cerrors.ErrPayloadFromSingleErr(principal, fmt.Errorf("one or more of the roles you want to assign is empty")))
		}

		if err := validateEnvVarRoles(role); err != nil {
			return authz.NewAssignRoleToUserForbidden().WithPayload(cerrors.ErrPayloadFromSingleErr(principal, fmt.Errorf("assigning: %w", err)))
		}
	}

	if err := h.validateUserIDForNamespaces(internalID); err != nil {
		return authz.NewAssignRoleToUserBadRequest().WithPayload(cerrors.ErrPayloadFromSingleErr(principal, err))
	}

	if err := h.validateUserTypeForNamespaces(params.Body.UserType); err != nil {
		return authz.NewAssignRoleToUserBadRequest().WithPayload(cerrors.ErrPayloadFromSingleErr(principal, err))
	}

	if len(params.Body.Roles) == 0 {
		return authz.NewAssignRoleToUserBadRequest().WithPayload(cerrors.ErrPayloadFromSingleErr(principal, fmt.Errorf("roles can not be empty")))
	}

	if err := h.authorizer.Authorize(ctx, principal, authorization.USER_AND_GROUP_ASSIGN_AND_REVOKE, authorization.Users(internalID)...); err != nil {
		return authz.NewAssignRoleToUserForbidden().WithPayload(cerrors.ErrPayloadFromSingleErr(principal, err))
	}

	roleNames, notFound, err := h.resolveAssignableRoles(principal, params.Body.Roles)
	if notFound {
		return authz.NewAssignRoleToUserNotFound().WithPayload(cerrors.ErrPayloadFromSingleErr(principal, fmt.Errorf("one or more of the roles requested doesn't exist")))
	}
	if err != nil {
		return authz.NewAssignRoleToUserBadRequest().WithPayload(cerrors.ErrPayloadFromSingleErr(principal, err))
	}

	if err := h.validateLocalRoleAssignment(principal, roleNames); err != nil {
		return authz.NewAssignRoleToUserForbidden().WithPayload(cerrors.ErrPayloadFromSingleErr(principal, err))
	}

View on GitHub (pinned to 75aa4b6d11)

Solutions

  1. Ensure the roles array has at least one non-empty role name before calling the API
  2. If the intent is to remove all roles, use the revoke-roles endpoint instead of assigning an empty list
  3. Add a client-side guard that skips the call when the roles list is empty

Example fix

// before
if len(roles) == 0 { roles = []string{} }
client.Users().Assigner().WithUser(id).WithRoles(roles...).Do(ctx)
// after
if len(roles) == 0 {
    return nil // or use the revoke endpoint; do not call assign with empty list
}
client.Users().Assigner().WithUser(id).WithRoles(roles...).Do(ctx)
Defensive patterns

Strategy: validation

Validate before calling

if len(roles) == 0 {
    return errors.New("refusing to assign empty roles list; use revoke endpoint to remove roles")
}

Prevention

When it happens

Trigger: POST /v1/users/{userId}/roles/assign with body {"roles": []} (or roles omitted/null) and a valid UserType — the empty list check at handlers_authz.go:812 fires.

Common situations: Clients serializing an empty Go/JS slice into the request body; frontend that sends the assign call even when no checkboxes are selected; code paths that build the roles list dynamically and end up empty (e.g. after filtering out invalid roles).

Related errors


AI-assisted analysis of weaviate/weaviate@75aa4b6d11 (2026-09-04). Data as JSON: /api/errors/fb12cb25d83978af. Report an issue: GitHub.