argoproj/argo-workflows · error
expected an array, got %v
Error message
expected an array, got %v
What it means
GetCustomGroup found the configured custom claim key in the RawClaim map but its value is not a JSON array. Custom SSO groups must be a list of strings; any other JSON type (string, object, number) hits this guard.
Source
Thrown at server/auth/types/claims.go:74
if localClaim.RawClaim["email_verified"] == true || localClaim.RawClaim["email_verified"] == "true" {
localClaim.EmailVerified = true
}
*c = Claims(localClaim)
return nil
}
// GetCustomGroup is responsible for extracting groups based on the
// provided custom claim key
func (c *Claims) GetCustomGroup(customKeyName string) ([]string, error) {
groups, ok := c.RawClaim[customKeyName]
if !ok {
return nil, fmt.Errorf("no claim found for key: %v", customKeyName)
}
sliceInterface, ok := groups.([]any)
if !ok {
return nil, fmt.Errorf("expected an array, got %v", groups)
}
newSlice := []string{}
for _, a := range sliceInterface {
val, ok := a.(string)
if !ok {
return nil, fmt.Errorf("group name %v was not a string", a)
}
newSlice = append(newSlice, val)
}
return newSlice, nil
}
func (c *Claims) GetUserInfoGroups(ctx context.Context, httpClient HTTPClient, accessToken, issuer, userInfoPath string) ([]string, error) {
url := fmt.Sprintf("%s%s", issuer, userInfoPath)
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
View on GitHub (pinned to 35bff19146)
Solutions
- Configure the IdP to always emit the claim as an array (even for a single value)
- Fix the claim/mapper mapping (Keycloak mapper type, Dex connector config) to produce JSON arrays
- Change customGroupClaimName to a claim that is genuinely an array
- Handle mixed scalar/array at ingestion if you control the code
Example fix
// before (token claim)
{ "groups": "team-a" }
// after (IdP mapper emits array)
{ "groups": ["team-a"] } Defensive patterns
Strategy: type-guard
Validate before calling
v, ok := claims.RawClaim[key].([]any)
if !ok { /* claim is not an array — fix IdP mapper or pick another claim */ } Type guard
func isArrayClaim(v any) bool {
_, ok := v.([]any)
return ok
} Try / catch
groups, err := claims.GetCustomGroup(key)
if err != nil {
return fmt.Errorf("group claim %q not an array: %w", key, err)
} Prevention
- Ensure the IdP emits arrays even for single membership
- Verify mapper output with a decoded token after each IdP change
- Prefer claims documented as multivalued
- Add a payload sample check in SSO integration tests
When it happens
Trigger: HandleCallback reads the custom group claim and the IdP emitted it as a single string (e.g. groups: "team-a") or an object/map rather than an array.
Common situations: IdPs that send a single group as a scalar when the user has one membership; misconfigured Dex/Keycloak mappers producing a comma-joined string instead of an array.
Related errors
- group name %v was not a string
- no claim found for key: %v
- failed to load system cert pool: %w
- failed to append certificates from PEM string
- not implemented
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/6e44ead6a9af6f37.
Report an issue: GitHub.