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

  1. Configure the IdP to always emit the claim as an array (even for a single value)
  2. Fix the claim/mapper mapping (Keycloak mapper type, Dex connector config) to produce JSON arrays
  3. Change customGroupClaimName to a claim that is genuinely an array
  4. 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

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


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/6e44ead6a9af6f37. Report an issue: GitHub.