gofr-dev/gofr · error

claim value is not an array

Error message

claim value is not an array

What it means

errClaimValueNotArray is returned by extractArrayClaim when the claim exists in the JWT but its value is not a JSON array ([]any). Array notation like "roles[0]" only works when the claim holds a list; a string, map, or scalar at that key triggers this error. It indicates the claim-path shape does not match the token's actual claim structure.

Source

Thrown at pkg/gofr/rbac/middleware.go:68

	errJWTClaimsNotFound = errors.New("JWT claims not found in request context")

	// errEmptyClaimPath is returned when claim path is empty.
	errEmptyClaimPath = errors.New("empty claim path")

	// errClaimPathNotFound is returned when a claim path is not found in JWT claims.
	errClaimPathNotFound = errors.New("claim path not found")

	// errInvalidArrayNotation is returned when array notation is invalid.
	errInvalidArrayNotation = errors.New("invalid array notation")

	// errInvalidArrayIndex is returned when array index is invalid.
	errInvalidArrayIndex = errors.New("invalid array index")

	// errClaimKeyNotFound is returned when a claim key is not found.
	errClaimKeyNotFound = errors.New("claim key not found")

	// errClaimValueNotArray is returned when a claim value is not an array.
	errClaimValueNotArray = errors.New("claim value is not an array")

	// errArrayIndexOutOfBounds is returned when array index is out of bounds.
	errArrayIndexOutOfBounds = errors.New("array index out of bounds")

	// errInvalidClaimStructure is returned when claim structure is invalid.
	errInvalidClaimStructure = errors.New("invalid claim structure")

	// errAuthorizationError is returned as a generic error message for unknown errors in traces.
	errAuthorizationError = errors.New("authorization error")
)

// Middleware creates an HTTP middleware function that enforces RBAC authorization.
// It extracts the user's role and checks if the role is allowed for the requested route.
//
//nolint:gocognit,gocyclo // Middleware complexity is acceptable due to multiple authorization paths
func Middleware(config *Config) func(handler http.Handler) http.Handler {
	return func(handler http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

View on GitHub (pinned to 187eb24962)

Solutions

  1. Inspect the decoded token and align JWTClaimPath with the actual value type: use a plain key path ("role") for strings, or navigate maps with dot notation ("realm_access.roles[0]").
  2. Ask the identity provider to always emit the claim as an array (multi-valued mapper) so the shape is stable.
  3. If the claim can legitimately be either string or array, handle both in a custom ErrorHandler or pre-normalize tokens.
  4. Update config when migrating IdPs — claim shapes rarely match one-to-one.

Example fix

// before (token has "role": "admin", a string)
config.JWTClaimPath = "role[0]"
// after
config.JWTClaimPath = "role"
Defensive patterns

Strategy: type-guard

Validate before calling

func rolesIsArray(claims jwt.MapClaims, key string) bool {
    _, ok := claims[key].([]any)
    return ok
}
// startup check against a sample token:
// if !rolesIsArray(sampleClaims, "roles") { log.Fatal("claim is not an array; use plain/dot path") }

Type guard

func isArrayClaim(v any) bool {
    _, ok := v.([]any)
    return ok
}

Try / catch

if err != nil && strings.Contains(err.Error(), "claim value is not an array") {
    logger.Warn("claim shape mismatch; adjust JWTClaimPath (string vs array)", "err", err)
    http.Error(w, "unauthorized", http.StatusUnauthorized)
    return
}

Prevention

When it happens

Trigger: JWTClaimPath "roles[0]" while the token contains "roles": "admin" (a plain string) or "roles": {"admin": true} (a map); extractArrayClaim's type assertion value.([]any) fails and the error is returned with the offending key name.

Common situations: Identity provider emits role as a single string for users with one role but as an array for multiple roles; switching IdPs where the equivalent claim is a map of role->bool (Keycloak realm_access.roles vs resource_access); path written for one token shape reused against another client's tokens.

Related errors


AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01). Data as JSON: /api/errors/d3ad906735a16a14. Report an issue: GitHub.