gohugoio/hugo · error
isn't a key of map type
Error message
%s isn't a key of map type %s
What it means
In the map branch of `evaluateSubElem` (where.go:377-382), Hugo builds a reflect.Value of the element name and tests `kv.Type().AssignableTo(obj.Type().Key())`. If the name's type is not assignable to the map's key type, the lookup cannot proceed and Hugo reports that the name is not a key of that map type. Note the name is always a string here, so this commonly means a non-string-keyed map.
Solutions
- If you need integer keys, restructure the data into a slice of structs with string fields before templating.
- Convert the map to `map[string]T` during data preparation.
- Use a different filtering strategy (range + index) instead of `where` on a non-string-keyed map.
Example fix
// before
{{ where $m "42" "==" v }} {{/* map[int]string */}}
// after
{{/* pre-convert to map[string]string or a slice of structs */}}
{{ where $items "ID" "==" "42" }} Defensive patterns
Strategy: validation
Validate before calling
// Go-side: ensure maps used with `where` have string keys
if t.Kind() == reflect.Map && t.Key().Kind() != reflect.String {
// convert to map[string]T or a slice of structs
} Prevention
- Use string-keyed maps for anything filtered in templates.
- Convert integer-keyed maps to slices of structs during data prep.
- Remember the where key path is always string-derived.
When it happens
Trigger: `{{ where $m "42" ... }}` against `map[int]string`; any map whose key type is not `string`, since the where key path is always string-derived.
Common situations: Filtering a `map[int]T` or `map[customType]T` by a string key from a template; assuming map keys are strings when they are integers.
Related errors
- is neither a struct field, a method nor a map element of…
- can't evaluate a nil pointer of type
- error at calling a method
- is a method of type but only returns an error type
- is a method of type but requires more than parameter
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/ced83b143fe00a65.
Report an issue: GitHub.
Appendix: source
Thrown at tpl/collections/where.go:382
return zero, fmt.Errorf("can't evaluate a nil pointer of type %s by a struct field or map key name %s", typ, elemName)
}
obj = reflect.Indirect(obj)
switch obj.Kind() {
case reflect.Struct:
ft, ok := obj.Type().FieldByName(elemName)
if ok {
if ft.PkgPath != "" && !ft.Anonymous {
return zero, fmt.Errorf("%s is an unexported field of struct type %s", elemName, typ)
}
return obj.FieldByIndex(ft.Index), nil
}
return zero, fmt.Errorf("%s isn't a field of struct type %s", elemName, typ)
case reflect.Map:
kv := reflect.ValueOf(elemName)
if kv.Type().AssignableTo(obj.Type().Key()) {
return obj.MapIndex(kv), nil
}
return zero, fmt.Errorf("%s isn't a key of map type %s", elemName, typ)
}
return zero, fmt.Errorf("%s is neither a struct field, a method nor a map element of type %s", elemName, typ)
}
// parseWhereArgs parses the end arguments to the where function. Return a
// match value and an operator, if one is defined.
func parseWhereArgs(args ...any) (mv reflect.Value, op string, err error) {
switch len(args) {
case 1:
mv = reflect.ValueOf(args[0])
case 2:
var ok bool
if op, ok = args[0].(string); !ok {
err = errors.New("operator argument must be string type")
return
}
op = strings.TrimSpace(strings.ToLower(op))
mv = reflect.ValueOf(args[1])View on GitHub (pinned to 52c9bd7908)