func foo() (err error) {
var x any
if x, err = bar(); err != nil {
goto fooError
}
if err = baz(x); err != nil {
goto fooError
}
if err = bat(); err != nil {
goto fooError
}
return
fooError:
return fmt.Errorf("%w doing foo <additional info here>", err)
}
Or: func foo() (err error) {
defer func() {
if err != nil {
err = fmt.Errorf("%w doing foo <additional info here>", err)
}
}()
var x any
if x, err = bar(); err != nil {
return
}
if err = baz(x); err != nil {
return
}
err = bat()
return
}
Seeking out different patterns is obviously most applicable in cases where error handling is actually doing something useful or more complicated than just wrapping the error.(My comment was meant to spur first principles discussion from intellectually curious folks, not "nobody does it that way" or "don't do that" edicts. Much of the argument against adding additional language features for error handling is that many of them aren't any better than what can be accomplished already, using existing syntax but different code style conventions. The goto pattern in particular is found all over the stdlib.)