{"record":{"id":"0700ba3e6ccffd20","repo":"gohugoio/hugo","slug":"v-0700ba","errorCode":null,"errorMessage":"%v","messagePattern":"%v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/internal/go_templates/texttemplate/hugo_template.go","lineNumber":303,"sourceCode":"\n\t// Err is the error returned by the function or method wrapped with \"try\".\n\t// This will always be nil if Value is set.\n\tErr *TryError\n}\n\n// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so\n// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0]\n// as the function itself.\nfunc (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node, name string, args []parse.Node, final reflect.Value, first ...reflect.Value) (val reflect.Value) {\n\t// Added for Hugo.\n\tif name == \"try\" {\n\t\tdefer func() {\n\t\t\tif r := recover(); r != nil {\n\t\t\t\t// Cause: herrors.Cause(err)\n\t\t\t\tif err, ok := r.(error); ok {\n\t\t\t\t\tval = reflect.ValueOf(TryValue{Value: nil, Err: newErrorWithCause(err)})\n\t\t\t\t} else {\n\t\t\t\t\tval = reflect.ValueOf(TryValue{Value: nil, Err: newErrorWithCause(fmt.Errorf(\"%v\", r))})\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t}\n\n\tif args != nil {\n\t\targs = args[1:] // Zeroth arg is function name/node; not passed to function.\n\t}\n\ttyp := fun.Type()\n\tnumFirst := len(first)        // Added for Hugo\n\tnumIn := len(args) + numFirst // Added for Hugo\n\tif !isMissing(final) {\n\t\tnumIn++\n\t}\n\tnumFixed := len(args) + len(first) // Adjusted for Hugo\n\tif typ.IsVariadic() {\n\t\tnumFixed = typ.NumIn() - 1 // last arg is the variadic one.\n\t\tif numIn < numFixed {","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/internal/go_templates/texttemplate/hugo_template.go#L285-L321","documentation":"Hugo adds a 'try' keyword to templates. When a function or method invoked under try panics, a deferred recover in evalCall wraps the value into a TryValue with an Err. This exact %v format string fires only when the recovered panic value is NOT an error type (e.g. panic with a string or int), so it is stringified generically. See hugo_template.go:296-307.","triggerScenarios":"{{ try (someFunc) }} where someFunc does panic(\"boom\") (a string) or panic(42) instead of returning an error or panicking with an error value.","commonSituations":"A custom Hugo template func/method that panics with a raw string rather than an error; a nil-pointer dereference inside a try block whose recovered runtime.Error is re-wrapped here.","solutions":["Make the panicking function return an error instead of panicking.","If it must panic, panic with an error value so the cause chain and TryError.Cause are preserved.","Inspect the TryValue.Err to handle the failure in the template rather than letting it propagate."],"exampleFix":"// before\nfunc badFunc() string { panic(\"nope\") }\n\n// after\nfunc badFunc() (string, error) { return \"\", errors.New(\"nope\") }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"// Narrow a TryValue returned by the 'try' template keyword.\n{{ with $tv := try $fn }}\n  {{ with $tv.Err }}ERR: {{ . }}{{ else }}OK: {{ $tv.Value }}{{ end }}\n{{ end }}","tryCatchPattern":"func recoverSafely(fn func() (any, error)) (v any, err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            if e, ok := r.(error); ok {\n                err = e\n            } else {\n                err = fmt.Errorf(\"%v\", r)\n            }\n        }\n    }()\n    return fn()\n}","preventionTips":["Prefer returning errors over panicking in functions exposed to templates.","When panicking is unavoidable, panic with an error value so the cause chain survives."],"tags":["template","hugo","panic","try","error-handling"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}