Producing Golang error backtraces / stacktraces

Why go does not have nice backtraces

Collecting stacktraces is expensive, so the core language will never implement them for everything.
If you need your code to be highly performant then consider making a error wrapper that can be turned on/off based on a environment variable.

Simple fix

  • import github.com/pkg/errors and use it instead of errors package (it is deprecated but works fine)
  • always errors.Wrap, errrors.New, or errors.Errorf from “github.com/pkg/errors” when passing from outside your code or creating errors
  • when subsequently passing errors along, a return err and DO NOT return fmt.Errorf("building foo: %w", err) (multiple wraps create multiple backtraces which is noisy but not a big problem, but using fmt.Errorf discards the backtrace)
  • in your main.go add this:
// go playground https://go.dev/play/p/n1gcwD-cv4K
import (
	"fmt"
	"github.com/pkg/errors"
)

type withStackTrace interface {
	StackTrace() errors.StackTrace
}

func main() {
	err := errors.New("example")
	err = errors.Wrap(err, "more context")
	if errWithStack, ok := err.(withStackTrace); ok {
		fmt.Fprintf(os.Stderr, "%+v\n", errWithStack)
	} else {
		fmt.Fprintln(os.Stderr, "Warning: unable to print stacktrace: use `errors.Wrap`")
	}
}

Nicer fix

Use a more complete solution like eris.

Leave a comment