hashicorp/nomad · error
%q list claim could not be converted to string list
Error message
%q list claim could not be converted to string list
What it means
extractListMappings expects each ListClaimMappings source claim to be a list (or a scalar that can be wrapped into a one-element list). If the raw value is a map or other non-convertible type, normalizeList fails and this error is returned.
Source
Thrown at lib/auth/claims.go:108
//
// {
// "/some/claim/pointer": "metadata_key1",
// "another_claim": "metadata_key2",
// ...
// }
func extractListMappings(
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
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Point the list claim mapping at the actual array, e.g. /resource_access/myclient/roles
- Decode the JWT and confirm the claim's shape before configuring mappings
- Use ClaimMappings (string) instead if the value is a single scalar
Example fix
// before
ListClaimMappings: {"/resource_access": "roles"}
// after
ListClaimMappings: {"/resource_access/api/roles": "roles"} Defensive patterns
Strategy: type-guard
Validate before calling
func isListShapedClaim(v interface{}) bool {
switch v.(type) {
case []interface{}, string, bool, float64:
return true
default:
return false // map[string]interface{} and similar fail
}
} Type guard
func asStringList(v interface{}) ([]string, bool) {
arr, ok := v.([]interface{})
if !ok {
if s, ok := v.(string); ok {
return []string{s}, true
}
return nil, false
}
out := make([]string, 0, len(arr))
for _, e := range arr {
s, ok := e.(string)
if !ok {
return nil, false
}
out = append(out, s)
}
return out, true
} Try / catch
if err != nil && strings.Contains(err.Error(), "could not be converted to string list") {
return fmt.Errorf("list claim mapping targets a non-list claim: %w", err)
} Prevention
- Point list mappings at actual JSON arrays, not objects like resource_access
- Decode a sample JWT and verify the claim is an array of scalars
- Handle single-element providers that collapse lists to scalars via the scalar branch
When it happens
Trigger: Login where a ListClaimMappings claim resolves to map[string]interface{} (an object) — e.g. mapping "/resource_access" (object of objects) directly as a list claim.
Common situations: Keycloak resource_access objects misconfigured as list claims; IdP emits a single-element list collapsed into a scalar of an unexpected type; claim schema changed on the provider side.
Related errors
- value %v in %q list claim could not be parsed as string
- error converting claim '%s' to string from unknown type %T
- no signed workload identity available
- JWT login returned an empty secret
- JWT login did not return a token
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/cda7da48b497fcb9.
Report an issue: GitHub.