gohugoio/hugo · error
%s is neither a struct field, a method nor a map element of
Error message
%s is neither a struct field, a method nor a map element of type %s
What it means
Fallback error in evaluateSubElem: the element is neither a struct nor a map (after indirection), and no method matched the key name — so there is no way to resolve a sub-element from it. Typical culprits are elements that are plain strings, numbers, or slices when the `where` key path expects addressable sub-fields.
Source
Thrown at tpl/collections/where.go:384
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])
default:
err = errors.New("can't evaluate the array by no match argument or more than or equal to two arguments")View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Verify the collection's element shape — `where` needs elements to be maps or structs; for scalar slices use `in` or `intersect` instead.
- Fix the data so each element is a map with the expected key.
- Shorten the key path so it stops at the struct/map level.
Example fix
<!-- before: tags is []string -->
{{ range where .Params.tags "Name" "go" }}
<!-- after -->
{{ if in .Params.tags "go" }} ... {{ end }} Defensive patterns
Strategy: validation
Validate before calling
{{ $first := index $c 0 }}
{{ if or (isset $first $key) (ne (printf "%v" $first) "") }}{{/* inspect with %#v first */}}{{ end }} Prevention
- Confirm the accessor exists as a field, method, or map key on the element type before writing the where clause
- For dotted paths like "Params.foo", validate each segment resolves on a sample element
- Keep collections homogeneous — mixed element types make one key fail on some elements
When it happens
Trigger: `where` applied to a collection of scalars, e.g. `where .Params.tags "Name" "x"` where tags is []string, or a dotted path whose intermediate segment resolves to a string/int/slice instead of a struct/map.
Common situations: Filtering a slice of strings as if it were a slice of objects; data files whose shape changed from list-of-maps to list-of-strings; applying `where` to `.Site.Taxonomies` values incorrectly.
Related errors
- %s isn't a key of map type %s
- arguments to complement must be slices or arrays
- can't iterate over %T
- invalid intersect values
- no such operator
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/453d8a863a77b7fc.json.
Report an issue: GitHub ↗.