Structured application errors for Go — with optional stack traces, cause chaining, key-value attributes, and rich fmt formatting.
Compatible with the standard library: errors.Is, errors.As, errors.Unwrap, and fmt.Errorf("%w", …) all work as expected.
go get github.com/wregis/errors| with stack trace | without stack trace | |
|---|---|---|
| new error | New(nil, "msg") |
NewSimple(nil, "msg") |
| wrap cause | Wrap(cause, "msg") |
WrapSimple(cause, "msg") |
Declare named error values with the standard library's errors.New — the idiomatic Go approach — and wrap them at the call site:
// mypackage/errors.go
var ErrNotFound = errors.New("not found")
var ErrForbidden = errors.New("forbidden")// mypackage/repository.go
func (r *Repo) FindUser(id int) (*User, error) {
u, ok := r.store[id]
if !ok {
return nil, werrors.Wrap(ErrNotFound, "user %d", id)
}
return u, nil
}// handler.go
err := repo.FindUser(id)
if errors.Is(err, repo.ErrNotFound) {
http.Error(w, "not found", http.StatusNotFound)
return
}The sentinel stays a plain, lightweight value. Wrap attaches the call-site context and stack trace without altering the sentinel itself.
// With stack trace
err := werrors.Wrap(cause, "read config")
err := werrors.Wrap(cause, "user %d", id) // fmt.Sprintf style
err := werrors.Wrap(cause, "") // reuse cause's message verbatim
// Without stack trace (cheaper)
err := werrors.WrapSimple(cause, "validation failed")Wrap and WrapSimple panic if cause is nil — use New / NewSimple when there is no cause to wrap.
err := werrors.New(nil, "something went wrong") // with stack trace
err := werrors.NewSimple(nil, "unknown command %q", cmd) // without stack traceerr := werrors.Wrap(ErrForbidden, "upload file")
err.AddAttribute("userID", userID)
err.AddAttribute("path", path)
// In a logging middleware:
if ae, ok := err.(werrors.Attributer); ok {
slog.Error("request failed", slog.Any("attrs", ae.Attributes()))
}All error types implement fmt.Formatter:
%s / %v message only
%q quoted message
%+v message + attributes + stack trace (if any) + cause chain
err := werrors.Wrap(cause, "query failed")
err.AddAttribute("table", "users")
fmt.Printf("%+v\n", err)
// query failed
// attributes:
// table = users
// stack trace:
// main.handleRequest
// /app/handler.go:42
// caused by: sql: no rows in result setErrors without a stack (NewSimple, WrapSimple) omit the stack trace section.
errors.go package doc · public interfaces · shared verbose formatter
stack.go New + appError (with stack trace)
simple.go NewSimple + simpleError (without stack trace)
wrap.go Wrap · WrapSimple
MIT — see LICENSE.