{"record":{"id":"cda7da48b497fcb9","repo":"hashicorp/nomad","slug":"q-list-claim-could-not-be-converted-to-string-lis","errorCode":null,"errorMessage":"%q list claim could not be converted to string list","messagePattern":"%q list claim could not be converted to string list","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/auth/claims.go","lineNumber":108,"sourceCode":"//\n//\t{\n//\t    \"/some/claim/pointer\": \"metadata_key1\",\n//\t    \"another_claim\": \"metadata_key2\",\n//\t     ...\n//\t}\nfunc extractListMappings(\n\tall map[string]interface{}, mappings map[string]string) (map[string][]string, error) {\n\n\tresult := make(map[string][]string)\n\tfor source, target := range mappings {\n\t\trawValue := getClaim(all, source)\n\t\tif rawValue == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\trawList, ok := normalizeList(rawValue)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"%q list claim could not be converted to string list\", source)\n\t\t}\n\n\t\tlist := make([]string, 0, len(rawList))\n\t\tfor _, raw := range rawList {\n\t\t\tvalue, ok := stringifyClaimValue(raw)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"value %v in %q list claim could not be parsed as string\",\n\t\t\t\t\traw, source)\n\t\t\t}\n\n\t\t\tif value == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tlist = append(list, value)\n\t\t}\n\n\t\tresult[target] = list\n\t}","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/lib/auth/claims.go#L90-L126","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nListClaimMappings: {\"/resource_access\": \"roles\"}\n// after\nListClaimMappings: {\"/resource_access/api/roles\": \"roles\"}","handlingStrategy":"type-guard","validationCode":"func isListShapedClaim(v interface{}) bool {\n    switch v.(type) {\n    case []interface{}, string, bool, float64:\n        return true\n    default:\n        return false // map[string]interface{} and similar fail\n    }\n}","typeGuard":"func asStringList(v interface{}) ([]string, bool) {\n    arr, ok := v.([]interface{})\n    if !ok {\n        if s, ok := v.(string); ok {\n            return []string{s}, true\n        }\n        return nil, false\n    }\n    out := make([]string, 0, len(arr))\n    for _, e := range arr {\n        s, ok := e.(string)\n        if !ok {\n            return nil, false\n        }\n        out = append(out, s)\n    }\n    return out, true\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"could not be converted to string list\") {\n    return fmt.Errorf(\"list claim mapping targets a non-list claim: %w\", err)\n}","preventionTips":["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"],"tags":["auth","oidc-claims","list-mapping"],"backgroundTag":"claim-type-unsupported","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}