{"record":{"id":"6ff679e25dac73d3","repo":"gohugoio/hugo","slug":"function-s-has-d-return-values-should-be-1-or-2","errorCode":null,"errorMessage":"function %s has %d return values; should be 1 or 2","messagePattern":"function (.+?) has (.+?) return values; should be 1 or 2","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/internal/go_templates/texttemplate/funcs.go","lineNumber":109,"sourceCode":"// call addValueFuncs first.\nfunc addFuncs(out, in FuncMap) {\n\tfor name, fn := range in {\n\t\tout[name] = fn\n\t}\n}\n\n// goodFunc reports whether the function or method has the right result signature.\nfunc goodFunc(name string, typ reflect.Type) error {\n\t// We allow functions with 1 result or 2 results where the second is an error.\n\tswitch numOut := typ.NumOut(); {\n\tcase numOut == 1:\n\t\treturn nil\n\tcase numOut == 2 && typ.Out(1) == errorType:\n\t\treturn nil\n\tcase numOut == 2:\n\t\treturn fmt.Errorf(\"invalid function signature for %s: second return value should be error; is %s\", name, typ.Out(1))\n\tdefault:\n\t\treturn fmt.Errorf(\"function %s has %d return values; should be 1 or 2\", name, typ.NumOut())\n\t}\n}\n\n// goodName reports whether the function name is a valid identifier.\nfunc goodName(name string) bool {\n\tif name == \"\" {\n\t\treturn false\n\t}\n\tfor i, r := range name {\n\t\tswitch {\n\t\tcase r == '_':\n\t\tcase i == 0 && !unicode.IsLetter(r):\n\t\t\treturn false\n\t\tcase !unicode.IsLetter(r) && !unicode.IsDigit(r):\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/internal/go_templates/texttemplate/funcs.go#L91-L127","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ntemplate.Funcs(template.FuncMap{\n    \"split3\": func(s string) (string, string, string) { ... }, // error\n})\n\n// after\ntemplate.Funcs(template.FuncMap{\n    \"split3\": func(s string) ([3]string, error) { return parts, nil },\n})","handlingStrategy":"validation","validationCode":"func checkReturnCounts(fm template.FuncMap) error {\n    for name, fn := range fm {\n        n := reflect.TypeOf(fn).NumOut()\n        if n < 1 || n > 2 {\n            return fmt.Errorf(\"%s returns %d values; need 1 or 2\", name, n)\n        }\n    }\n    return nil\n}","typeGuard":"func hasValidArity(fn any) bool {\n    t := reflect.TypeOf(fn)\n    if t.Kind() != reflect.Func { return false }\n    return t.NumOut() == 1 || t.NumOut() == 2\n}","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        log.Printf(\"func arity invalid: %v\", r)\n    }\n}()\nt.Funcs(fm)","preventionTips":["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."],"tags":["go","text-template","funcs","reflect","signature"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}