Go1 13 Errors
For me, Go 1.13 arrived with anticipation of better error handling. Presently, the second Google search result for Go 1.13 error hanlding is an article that refers to the “xerrors” package. One feature of the xerrors package is that it produced errors with a stack trace showing where the error came from. The addition to Go 1.13, however, did not include this particular feature, and left me spending frustrating hours trying to debug the loss of stack trace after switching from xerrors to the standard library.
What if you do want a stack trace in your error? You’ll have to code it into your own exceptions. A custom error with stack trace can look like this:
package main
import (
"bytes"
"fmt"
"runtime"
)
func main() {
fmt.Println(NewStackTraceError("an error"))
}
type StackTraceError struct {
message string
frames []string
}
func NewStackTraceError(message string) *StackTraceError {
// top frames are: runtime.Caller, NewStackTraceError (this), caller of NewStackTraceError
// so we skip two out of three frames
skipFrames := 2
pc := make([]uintptr, 1)
n := runtime.Callers(skipFrames, pc)
if n == 0 {
return &StackTraceError{message: message}
}
frames := make([]string, 0)
f := runtime.CallersFrames(pc)
if f != nil {
for {
frame, more := f.Next()
frames = append(frames, fmt.Sprintf(" %s (%s):%d", frame.File, frame.Function, frame.Line))
if !more {
break
}
}
}
return &StackTraceError{
message: message,
frames: frames,
}
}
func (e *StackTraceError) Error() string {
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "%v\n", e.message)
for _, f := range e.frames {
fmt.Fprintf(buf, " %s\n", f)
}
return buf.String()
}
Try it out in the Go Playground here.