hashicorp/nomad · error

value %v in %q list claim could not be parsed as string

Error message

value %v in %q list claim could not be parsed as string

What it means

extractListMappings converted the claim to a list, but one element inside it has a type stringifyClaimValue cannot stringify (e.g. a nested map/object element). The whole list extraction fails for that mapping.

Source

Thrown at lib/auth/claims.go:115

	all map[string]interface{}, mappings map[string]string) (map[string][]string, error) {

	result := make(map[string][]string)
	for source, target := range mappings {
		rawValue := getClaim(all, source)
		if rawValue == nil {
			continue
		}

		rawList, ok := normalizeList(rawValue)
		if !ok {
			return nil, fmt.Errorf("%q list claim could not be converted to string list", source)
		}

		list := make([]string, 0, len(rawList))
		for _, raw := range rawList {
			value, ok := stringifyClaimValue(raw)
			if !ok {
				return nil, fmt.Errorf("value %v in %q list claim could not be parsed as string",
					raw, source)
			}

			if value == "" {
				continue
			}
			list = append(list, value)
		}

		result[target] = list
	}

	return result, nil
}

// getClaim returns a claim value from allClaims given a provided claim string.
// If this string is a valid JSONPointer, it will be interpreted as such to
// locate the claim. Otherwise, the claim string will be used directly.

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Use a JSON pointer to the scalar field within each element if the provider supports it (often not possible for arrays of objects) — otherwise expose a flat string array claim at the IdP
  2. Configure a transformer/mapper at the IdP (e.g. Keycloak token mapper) to emit a plain array of strings
  3. Identify the offending element from the %v value printed in the error

Example fix

// IdP emits [{"name":"admin"},{"name":"reader"}]
// after: mapper emits ["admin","reader"]
ListClaimMappings: {"/groups": "groups"}
Defensive patterns

Strategy: type-guard

Validate before calling

func allElementsScalar(arr []interface{}) bool {
    for _, e := range arr {
        switch e.(type) {
        case string, bool, float64:
        default:
            return false
        }
    }
    return true
}

Type guard

func elemAsString(e interface{}) (string, bool) {
    s, ok := e.(string)
    return s, ok
}

Try / catch

if err != nil && strings.Contains(err.Error(), "could not be parsed as string") {
    return fmt.Errorf("list claim contains non-scalar element: %w", err)
}

Prevention

When it happens

Trigger: A list claim containing non-scalar entries, e.g. roles as array of objects [{"name":"admin"}] mapped directly via ListClaimMappings.

Common situations: Array-of-objects claims from enterprise IdPs (groups as [{id, name}]); mixed-type arrays where one entry is a JSON object.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/c11615424dada971. Report an issue: GitHub.