gohugoio/hugo · error
can't evaluate an invalid value
Error message
can't evaluate an invalid value
What it means
The `where` and `sort` functions walk a dotted key path (e.g. `.Author.Name`) by calling `evaluateSubElem` for each segment. If an intermediate reflect.Value is not valid (`!obj.IsValid()`), the field/method/map navigation cannot proceed and this error fires. An invalid Value typically results from a missing map key or an absent struct field on a prior path segment.
Solutions
- Ensure all elements share the same structure for the given key path.
- Use a single-level key or flatten the data so the path always resolves.
- Filter the collection first to items that have the nested field, then apply `where`.
Example fix
// before
{{ where .Pages "Author.Name" "eq" "Alice" }}
// after
{{ $withAuthor := where .Pages "Author" "ne" nil }}
{{ where $withAuthor "Author.Name" "eq" "Alice" }} Defensive patterns
Strategy: validation
Validate before calling
// Pre-filter elements that have the nested key before applying a dotted path
{{ $hasKey := where .Pages "Author" "ne" nil }}
{{ where $hasKey "Author.Name" "eq" "Alice" }} Type guard
func pathResolvesOnAll(elemType reflect.Type, path []string) bool {
t := elemType
if t.Kind() == reflect.Pointer { t = t.Elem() }
for _, seg := range path {
switch t.Kind() {
case reflect.Struct:
f, ok := t.FieldByName(seg)
if !ok { return false }
t = f.Type
case reflect.Map:
t = t.Elem()
default:
return false
}
if t.Kind() == reflect.Pointer { t = t.Elem() }
}
return true
} Prevention
- Ensure all elements share the structure needed by the dotted key path.
- Pre-filter to elements that have the top-level key before drilling deeper.
- Avoid dotted paths over heterogeneous collections.
When it happens
Trigger: Calling `{{ where .Pages "Author.Name" "eq" "Alice" }}` where some pages have no `Author` map (so `.Author` yields an invalid zero Value), or using a dotted path where a middle segment does not exist on the element type.
Common situations: Heterogeneous collections where some items have a nested field and others do not. The developer expects missing keys to be skipped but the evaluation short-circuits on the invalid intermediate value.
Related errors
- can't evaluate the array by no match argument or more than…
- can't iterate over a nil value of type
- can't iterate over %T
- invalid intersect values
- no such operator
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/70ad562a17e74c54.
Report an issue: GitHub.
Appendix: source
Thrown at tpl/collections/where.go:314
if svp != nil && smvp != nil {
re, err := hstrings.GetOrCompileRegexp(*smvp)
if err != nil {
return false, err
}
if re.MatchString(*svp) {
return true, nil
}
return false, nil
}
default:
return false, errors.New("no such operator")
}
return false, nil
}
func evaluateSubElem(ctx, obj reflect.Value, elemName string) (reflect.Value, error) {
if !obj.IsValid() {
return zero, errors.New("can't evaluate an invalid value")
}
typ := obj.Type()
obj, isNil := hreflect.Indirect(obj)
// first, check whether obj has a method. In this case, obj is
// a struct or its pointer. If obj is a struct,
// to check all T and *T method, use obj pointer type Value
objPtr := obj
if !hreflect.IsInterfaceOrPointer(objPtr.Kind()) && objPtr.CanAddr() {
objPtr = objPtr.Addr()
}
mt := hreflect.GetMethodByNameForType(objPtr.Type(), elemName)
if mt.Func.IsValid() {
// Receiver is the first argument.
args := []reflect.Value{objPtr}
num := mt.Type.NumIn()View on GitHub (pinned to 52c9bd7908)