gohugoio/hugo · error
%s is a method of type %s but only returns an error type
Error message
%s is a method of type %s but only returns an error type
What it means
When a method returns exactly one value and that value implements the `error` interface, `evaluateSubElem` (where.go:348-349) rejects it. A sole error return gives no usable value to compare, so using it as a where key is meaningless.
Source
Thrown at tpl/collections/where.go:349
args := []reflect.Value{objPtr}
num := mt.Type.NumIn()
maxNumIn := 1
if num > 1 && hreflect.IsContextType(mt.Type.In(1)) {
args = append(args, ctx)
maxNumIn = 2
}
switch {
case mt.PkgPath != "":
return zero, fmt.Errorf("%s is an unexported method of type %s", elemName, typ)
case mt.Type.NumIn() > maxNumIn:
return zero, fmt.Errorf("%s is a method of type %s but requires more than %d parameter", elemName, typ, maxNumIn)
case mt.Type.NumOut() == 0:
return zero, fmt.Errorf("%s is a method of type %s but returns no output", elemName, typ)
case mt.Type.NumOut() > 2:
return zero, fmt.Errorf("%s is a method of type %s but returns more than 2 outputs", elemName, typ)
case mt.Type.NumOut() == 1 && mt.Type.Out(0).Implements(errorType):
return zero, fmt.Errorf("%s is a method of type %s but only returns an error type", elemName, typ)
case mt.Type.NumOut() == 2 && !mt.Type.Out(1).Implements(errorType):
return zero, fmt.Errorf("%s is a method of type %s returning two values but the second value is not an error type", elemName, typ)
}
res := mt.Func.Call(args)
if len(res) == 2 && !res[1].IsNil() {
return zero, fmt.Errorf("error at calling a method %s of type %s: %s", elemName, typ, res[1].Interface().(error))
}
return res[0], nil
}
// elemName isn't a method so next start to check whether it is
// a struct field or a map value. In both cases, it mustn't be
// a nil value
if isNil {
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() {View on GitHub (pinned to 52c9bd7908)
Solutions
- Pre-filter the slice in Go before handing it to the template, producing a `Valid bool` field.
- Add a method returning the validation result as a non-error value (e.g. `IsValid() bool`).
- Compute and store validity as a field during data preparation.
Example fix
// before
{{ where $items "Validate" "==" nil }} {{/* Validate() error */}}
// after
{{ where $items "IsValid" "==" true }} {{/* IsValid() bool */}} Defensive patterns
Strategy: validation
Validate before calling
// Go-side: a sole-error return is unusable as a where key
mt, ok := reflect.TypeOf(item).MethodByName(name)
if ok && mt.Type.NumOut() == 1 {
ok = !mt.Type.Out(0).Implements(reflect.TypeFor[error]())
} Prevention
- Don't use validator (error-only) methods as `where` keys.
- Expose validity as `IsValid() bool` instead.
- Keep error returns paired with a value, or stand alone only outside templates.
When it happens
Trigger: `{{ where $items "Validate" "==" nil }}` against `func (i) Validate() error`.
Common situations: Trying to filter a collection to valid/invalid items by calling a validator method directly; misunderstanding that `where` needs a value, not a status-only return.
Related errors
- %s is a method of type %s but requires more than %d paramete
- %s is a method of type %s but returns no output
- %s is a method of type %s but returns more than 2 outputs
- %s is a method of type %s returning two values but the secon
- %s is an unexported method of type %s
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/a9233853316eebe6.
Report an issue: GitHub.