caddyserver/caddy · error

unsupported value type in matcher input: %T

Error message

unsupported value type in matcher input: %T

What it means

Thrown when converting CEL matcher input maps to map[string][]string: a value is a []ref.Val (a CEL list) but one of its elements is not a types.String (e.g. an int or bool CEL value). Since header values must be strings, the element cannot be converted.

Solutions

  1. Make all list elements in the matcher map strings (quote numbers/booleans)
  2. Validate the matcher input map is map[string][]string-shaped before passing it to the CEL matcher
  3. Simplify the expression to use explicit string literals

Example fix

// before
{'accept': [1, 'gzip']}
// after
{'accept': ['1', 'gzip']}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure every header matcher value is []string of strings before serializing
func isStringSlice(v any) bool {
    s, ok := v.([]string)
    return ok && len(s) >= 0
}

Prevention

When it happens

Trigger: A CEL matcher whose map value is a heterogeneous list, e.g. {'x': [1, 'a']} — the []ref.Val case iterates elements and requires each to be types.String; an int element fails the type assertion.

Common situations: CEL expressions mixing types in lists used as header matcher input; configs written by tools that emit JSON numbers where header values are expected.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/dbc3fa50137c13ad. Report an issue: GitHub.

Appendix: source

Thrown at modules/caddyhttp/celmatcher.go:707

		}
	} else {
		mapStrIface = mapStrRaw.(map[string]any)
	}
	mapStrListStr := make(map[string][]string, len(mapStrIface))
	for k, v := range mapStrIface {
		switch val := v.(type) {
		case string:
			mapStrListStr[k] = []string{val}
		case types.String:
			mapStrListStr[k] = []string{string(val)}
		case []string:
			mapStrListStr[k] = val
		case []ref.Val:
			convVals := make([]string, len(val))
			for i, elem := range val {
				strVal, ok := elem.(types.String)
				if !ok {
					return nil, fmt.Errorf("unsupported value type in matcher input: %T", val)
				}
				convVals[i] = string(strVal)
			}
			mapStrListStr[k] = convVals
		case []any:
			convVals := make([]string, len(val))
			for i, elem := range val {
				switch e := elem.(type) {
				case string:
					convVals[i] = e
				case types.String:
					convVals[i] = string(e)
				default:
					return nil, fmt.Errorf("unsupported element type in matcher input list: %T", elem)
				}
			}
			mapStrListStr[k] = convVals
		default:

View on GitHub (pinned to 50e54ee279)