gohugoio/hugo · error
function %s has %d return values; should be 1 or 2
Error message
function %s has %d return values; should be 1 or 2
What it means
Returned/panicked by goodFunc when a registered function has zero or three-or-more return values. text/template FuncMap values must return exactly one value, or two values (the second being error). The %s is the func name; %d is the actual number of return values.
Source
Thrown at tpl/internal/go_templates/texttemplate/funcs.go:109
// call addValueFuncs first.
func addFuncs(out, in FuncMap) {
for name, fn := range in {
out[name] = fn
}
}
// goodFunc reports whether the function or method has the right result signature.
func goodFunc(name string, typ reflect.Type) error {
// We allow functions with 1 result or 2 results where the second is an error.
switch numOut := typ.NumOut(); {
case numOut == 1:
return nil
case numOut == 2 && typ.Out(1) == errorType:
return nil
case numOut == 2:
return fmt.Errorf("invalid function signature for %s: second return value should be error; is %s", name, typ.Out(1))
default:
return fmt.Errorf("function %s has %d return values; should be 1 or 2", name, typ.NumOut())
}
}
// goodName reports whether the function name is a valid identifier.
func goodName(name string) bool {
if name == "" {
return false
}
for i, r := range name {
switch {
case r == '_':
case i == 0 && !unicode.IsLetter(r):
return false
case !unicode.IsLetter(r) && !unicode.IsDigit(r):
return false
}
}
return trueView on GitHub (pinned to 52c9bd7908)
Solutions
- Reduce the function to return exactly 1 value, or 2 values with the second being error.
- Wrap extra outputs into a single struct/value returned as the primary result.
- Add a unit test asserting each Funcs entry satisfies goodFunc before use.
- Document the (1) or (value, error) contract next to every registered func.
Example fix
// before
template.Funcs(template.FuncMap{
"split3": func(s string) (string, string, string) { ... }, // error
})
// after
template.Funcs(template.FuncMap{
"split3": func(s string) ([3]string, error) { return parts, nil },
}) Defensive patterns
Strategy: validation
Validate before calling
func checkReturnCounts(fm template.FuncMap) error {
for name, fn := range fm {
n := reflect.TypeOf(fn).NumOut()
if n < 1 || n > 2 {
return fmt.Errorf("%s returns %d values; need 1 or 2", name, n)
}
}
return nil
} Type guard
func hasValidArity(fn any) bool {
t := reflect.TypeOf(fn)
if t.Kind() != reflect.Func { return false }
return t.NumOut() == 1 || t.NumOut() == 2
} Try / catch
defer func() {
if r := recover(); r != nil {
log.Printf("func arity invalid: %v", r)
}
}()
t.Funcs(fm) Prevention
- Design template funcs to return 1 or (value, error) only.
- Wrap multi-value helpers into a single struct return.
- Add a FuncMap validation test that recovers and reports each bad entry.
When it happens
Trigger: Registering a func via Funcs/addValueFuncs whose reflect type has NumOut() != 1 and != 2 (e.g. a func returning nothing, or returning three values). Also surfaces at execution via evalCall/the call builtin as an ExecError.
Common situations: A helper returning (a, b, c); a void action func returning nothing; passing a method value whose signature has multiple returns; accidental registration of a non-function-shaped value that resolves to an odd arity.
Related errors
- invalid function signature for %s: second return value shoul
- value is nil; should be of type %s
- value has type %s; should be %s
- cannot index slice/array with nil
- cannot index slice/array with type %s
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/6ff679e25dac73d3.
Report an issue: GitHub.