{"record":{"id":"12d739bd02026e9d","repo":"gohugoio/hugo","slug":"v","errorCode":null,"errorMessage":"%v","messagePattern":"%v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/internal/go_templates/texttemplate/funcs.go","lineNumber":362,"sourceCode":"\t\t}\n\n\t\tvar err error\n\t\tif argv[i], err = prepareArg(arg, argType); err != nil {\n\t\t\treturn reflect.Value{}, fmt.Errorf(\"arg %d: %w\", i, err)\n\t\t}\n\t}\n\treturn safeCall(fn, argv)\n}\n\n// safeCall runs fun.Call(args), and returns the resulting value and error, if\n// any. If the call panics, the panic value is returned as an error.\nfunc safeCall(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tif e, ok := r.(error); ok {\n\t\t\t\terr = e\n\t\t\t} else {\n\t\t\t\terr = fmt.Errorf(\"%v\", r)\n\t\t\t}\n\t\t}\n\t}()\n\tret := fun.Call(args)\n\tif len(ret) == 2 && !ret[1].IsNil() {\n\t\treturn ret[0], ret[1].Interface().(error)\n\t}\n\treturn ret[0], nil\n}\n\n// Boolean logic.\n\nfunc truth(arg reflect.Value) bool {\n\tt, _ := isTrue(indirectInterface(arg))\n\treturn t\n}\n\n// and computes the Boolean AND of its arguments, returning","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/internal/go_templates/texttemplate/funcs.go#L344-L380","documentation":"Raised by `safeCall` when the invoked function panics (funcs.go:356-364). The panic value is recovered and returned as a template-execution error formatted with `%v`. This surfaces arbitrary panics from user-supplied FuncMap entries or builtins as template errors rather than crashing the process.","triggerScenarios":"A registered FuncMap entry that panics (nil deref, index-out-of-range, divide-by-zero, explicit `panic()`); a method called via template that performs an unsafe operation on its inputs.","commonSituations":"Buggy custom template functions; funcs that assume non-nil input but receive nil from templates; integer division by zero in a helper; third-party Hugo module exposing a panicking func.","solutions":["Reproduce the call in Go and fix the panic at its source (the function body).","Add nil/error checks in the func and return a proper `error` (the (value, error) return convention) instead of panicking.","Validate inputs in the template before calling.","Pin or upgrade the module exposing the panicking function."],"exampleFix":"// before (Go func)\nfunc first(s []string) string { return s[0] }   // panics on empty\n\n// after\nfunc first(s []string) (string, error) {\n    if len(s) == 0 { return \"\", errors.New(\"empty slice\") }\n    return s[0], nil\n}","handlingStrategy":"try-catch","validationCode":"// Validate inputs in-template before calling:\n//   {{if .S}}{{call .First .S}}{{end}}\n// Better: fix the func to return (value, error) and check inputs.","typeGuard":null,"tryCatchPattern":"// safeCall already recovers panics into errors; surface them:\n// In Go rendering code:\nerr := tmpl.Execute(w, data)\nif err != nil {\n    var pe *template.Error\n    if errors.As(err, &pe) {\n        log.Printf(\"template exec error: %v\", pe)\n    }\n    return err\n}","preventionTips":["Make custom FuncMap entries return (value, error) and never panic.","Add nil/bounds checks inside funcs called from templates.","Reproduce panicking funcs in isolation under tests."],"tags":["template","call","panic","recovery","text-template"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}