Just using WithStack() from "github.com/pkg/errors" on any error that originates from outside my repository has been my go-to rule for any Go project. It has never disappointed.
The similarity in both needing to have stack trace does not make them very alike yet. They serve similar purpose and for that purpose the stack trace serves value to the developer.
Returns go straight up the stack only if you choose them to. Caller doesn't have to propagate errors and return immediately, it can hold onto them and/or process them in the natural place they occur, they are just values. The returns from your function can be found with "grep return".
Exceptions, by default, break the natural control flow unless you wrap everything with try/catch. Even then, a lot of constructs won't be very natural and you really will have to get out of your way to identify the source of the exception, which very frequently is more important than it's type.
Why would finding the source of the exception be difficult? The stack trace in exception-based languages goes back to the actual line, as opposed to a stack trace from an error-as-value based language, where it only goes to where you trigger generating the stack trace.
I meant finding it in the context of a coder who writes a function. It's hard to identify which expression and statements can cause exceptions and effectively short-circuit your function. In contrast to explicit errors-returned-as-values.
(Panics of course can cause similar thing in Go but that's the reason why they should rarely be recovered and not used as a value propagation mechanism.)