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

  1. Verify the collection's element shape — `where` needs elements to be maps or structs; for scalar slices use `in` or `intersect` instead.
  2. Fix the data so each element is a map with the expected key.
  3. 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

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


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/453d8a863a77b7fc.json. Report an issue: GitHub ↗.