{"record":{"id":"fb42ef13308565b2","repo":"caddyserver/caddy","slug":"unsupported-map-key-type-in-header-match-t","errorCode":null,"errorMessage":"unsupported map key type in header match: %T","messagePattern":"unsupported map key type in header match: %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/celmatcher.go","lineNumber":686,"sourceCode":"// of string.\nfunc CELValueToMapStrList(data ref.Val) (map[string][]string, error) {\n\t// Prefer map[string]any, but newer cel-go versions may return map[any]any\n\tmapStrType := reflect.TypeFor[map[string]any]()\n\tmapStrRaw, err := data.ConvertToNative(mapStrType)\n\tvar mapStrIface map[string]any\n\tif err != nil {\n\t\t// Try map[any]any and convert keys to strings\n\t\tmapAnyType := reflect.TypeFor[map[any]any]()\n\t\tmapAnyRaw, err2 := data.ConvertToNative(mapAnyType)\n\t\tif err2 != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tmapAnyIface := mapAnyRaw.(map[any]any)\n\t\tmapStrIface = make(map[string]any, len(mapAnyIface))\n\t\tfor k, v := range mapAnyIface {\n\t\t\tks, ok := k.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"unsupported map key type in header match: %T\", k)\n\t\t\t}\n\t\t\tmapStrIface[ks] = v\n\t\t}\n\t} else {\n\t\tmapStrIface = mapStrRaw.(map[string]any)\n\t}\n\tmapStrListStr := make(map[string][]string, len(mapStrIface))\n\tfor k, v := range mapStrIface {\n\t\tswitch val := v.(type) {\n\t\tcase string:\n\t\t\tmapStrListStr[k] = []string{val}\n\t\tcase types.String:\n\t\t\tmapStrListStr[k] = []string{string(val)}\n\t\tcase []string:\n\t\t\tmapStrListStr[k] = val\n\t\tcase []ref.Val:\n\t\t\tconvVals := make([]string, len(val))\n\t\t\tfor i, elem := range val {","sourceCodeStart":668,"sourceCodeEnd":704,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/celmatcher.go#L668-L704","documentation":"Thrown while converting a CEL-evaluated map into map[string]any for a header match in the CEL matcher. The expression produced a map whose key type is not a Go string (e.g. an int or bool key after ConvertToNative to map[any]any), so the key cannot be used as an HTTP header name. Caddy rejects it because HTTP header names must be strings.","triggerScenarios":"Writing a CEL expression matcher whose header-map input is built from a map literal with non-string keys, e.g. {header_match: {1: 'v'}} or a map produced by a CEL function returning non-string keys; the code path first tries ConvertToNative(map[string]any), fails, retries map[any]any, and hits a non-string key.","commonSituations":"Hand-written JSON configs with CEL matchers where map keys were accidentally quoted as numbers/booleans; programmatically generated matcher configs from YAML/JSON tooling that types header names as non-strings.","solutions":["Make every key in the matcher's map a string literal (quote keys: {\"Accept\": [\"text/html\"]})","If generating config from code, serialize maps with string keys only (use map[string][]string in Go)","Check the CEL expression for computed map constructions and replace them with literal string keys"],"exampleFix":"// before\n{\"expression\": \"{1: 'v'}.all(k, k)\"}\n// after\n{\"expression\": \"{'accept': 'v'}['accept'] == 'v'\"}","handlingStrategy":"validation","validationCode":"// Go: validate matcher input maps have string keys before building config\nfunc checkKeysString(m any) error {\n    rv := reflect.ValueOf(m)\n    if rv.Kind() != reflect.Map || rv.Type().Key().Kind() != reflect.String {\n        return fmt.Errorf(\"map keys must be strings, got %v\", rv.Type())\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always quote header names in matcher maps","Generate configs with map[string][]string in Go rather than any-typed maps","Run caddy adapt + caddy validate on generated configs in CI"],"tags":["caddy","cel","matcher","headers","config"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}