Skip to content
wregisPublic

About

Error handling fo Go

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

go-errors

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.

Install

go get github.com/wregis/errors

Constructors at a glance

with stack trace without stack trace
new error New(nil, "msg") NewSimple(nil, "msg")
wrap cause Wrap(cause, "msg") WrapSimple(cause, "msg")

Sentinel errors

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.

Wrapping

// 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.

Creating errors without a cause

err := werrors.New(nil, "something went wrong")          // with stack trace
err := werrors.NewSimple(nil, "unknown command %q", cmd) // without stack trace

Attributes

err := 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()))
}

Formatting

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 set

Errors without a stack (NewSimple, WrapSimple) omit the stack trace section.

File layout

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

License

MIT — see LICENSE.

About

Error handling fo Go

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages