Go 1.13+ compatible error wrapping with call stacks and function parameters.
- Automatic call stack capture - Every error wrapped with this package includes the full call stack at the point where the error was created or wrapped
- Function parameter tracking - Capture and display function parameters in error messages for detailed debugging
- Go 1.13+ error wrapping compatible - Works seamlessly with
errors.Is,errors.As, anderrors.Unwrap - Zero allocation optimization - Specialized functions for 0-10 parameters to avoid varargs allocations
- Helper utilities - Common patterns for NotFound errors, context errors, and panic recovery
- Customizable formatting - Control how sensitive data appears in error messages
- Go 1.23+ iterator support - Convert errors to iterators for functional programming patterns
go get github.com/domonda/go-errsimport "github.com/domonda/go-errs"
func DoSomething() error {
return errs.New("something went wrong")
}
// Error output includes call stack:
// something went wrong
// main.DoSomething
// /path/to/file.go:123The most powerful feature - automatically capture function parameters when errors occur:
func ProcessUser(userID string, age int) (err error) {
defer errs.WrapWithFuncParams(&err, userID, age)
if age < 0 {
return errors.New("invalid age")
}
return database.UpdateUser(userID, age)
}
// When an error occurs, output includes:
// invalid age
// main.ProcessUser("user-123", -5)
// /path/to/file.go:45func LoadConfig(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return errs.Errorf("failed to read config: %w", err)
}
// ... parse data
return nil
}errs.New(text)- Create a new error with call stackerrs.Errorf(format, ...args)- Format an error with call stack (supports%wfor wrapping)errs.Sentinel(text)- Create a const-able sentinel error
errs.WrapWithFuncParams(&err, params...)- Most common: wrap error with function parameterserrs.WrapWith0FuncParams(&err)througherrs.WrapWith10FuncParams(&err, p0, ...)- Optimized variants for specific parameter countserrs.WrapWithFuncParamsSkip(skip, &err, params...)- Advanced: control stack frame skipping
errs.WrapWithCallStack(err)- Wrap error with call stack onlyerrs.WrapWithCallStackSkip(skip, err)- Advanced: control stack frame skipping
Standardized "not found" error handling compatible with sql.ErrNoRows and os.ErrNotExist:
var ErrUserNotFound = fmt.Errorf("user %w", errs.ErrNotFound)
func GetUser(id string) (*User, error) {
user, err := db.Query("SELECT * FROM users WHERE id = ?", id)
if errs.IsErrNotFound(err) {
return nil, ErrUserNotFound
}
return user, err
}
// Check for any "not found" variant
if errs.IsErrNotFound(err) {
// Handle not found case
}// Check if context is done
if errs.IsContextDone(ctx) {
// Handle context done
}
// Check specific context errors
if errs.IsContextCanceled(ctx) {
// Handle cancellation
}
if errs.IsContextDeadlineExceeded(ctx) {
// Handle timeout
}
// Check if an error is context-related
if errs.IsContextError(err) {
// Don't retry context errors
}func RiskyOperation() (err error) {
defer errs.RecoverPanicAsError(&err)
// If this panics, it will be converted to an error
return doSomethingRisky()
}
// With function parameters
func ProcessItem(id string) (err error) {
defer errs.RecoverPanicAsErrorWithFuncParams(&err, id)
return processItem(id) // May panic
}type CustomError struct {
error
}
func (e CustomError) ShouldLog() bool {
return false // Don't log this error
}
// Check if error should be logged
if errs.ShouldLog(err) {
logger.Error(err)
}
// Wrap error to prevent logging
err = errs.DontLog(err)Implement CallStackPrintable to control how your types appear in error messages:
type Password struct {
value string
}
func (p Password) PrintForCallStack(w io.Writer) {
w.Write([]byte("***REDACTED***"))
}
func Login(username string, pwd Password) (err error) {
defer errs.WrapWithFuncParams(&err, username, pwd)
// Error messages will show: Login("admin", ***REDACTED***)
return authenticate(username, pwd)
}// Check if error chain contains a specific type
if errs.Has[*DatabaseError](err) {
// Handle database error
}
// Get all errors of a specific type from the chain
dbErrors := errs.As[*DatabaseError](err)
for _, dbErr := range dbErrors {
// Handle each database error
}
// Check error type without custom Is/As methods
if errs.Type[*DatabaseError](err) {
// Error is or wraps a DatabaseError
}// Get the root cause error
rootErr := errs.Root(err)
// Unwrap call stack information only
plainErr := errs.UnwrapCallStack(err)// Convert error to single-value iterator
for err := range errs.IterSeq(myErr) {
// Process error
}
// Convert error to two-value iterator (value, error) pattern
for val, err := range errs.IterSeq2[MyType](myErr) {
if err != nil {
// Handle error
}
}// Change path prefix trimming
errs.TrimFilePathPrefix = "/go/src/"
// Adjust maximum stack depth
errs.MaxCallStackFrames = 64 // Default is 32// Replace the global formatter
errs.FormatFunctionCall = func(function string, params ...any) string {
// Your custom formatting logic
return fmt.Sprintf("%s(%v)", function, params)
}func MyFunc(id string) (err error) {
defer errs.WrapWithFuncParams(&err, id)
// Function body
}// Instead of:
defer errs.WrapWithFuncParams(&err, p0, p1, p2)
// Use:
defer errs.WrapWith3FuncParams(&err, p0, p1, p2)type APIKey string
func (k APIKey) PrintForCallStack(w io.Writer) {
io.WriteString(w, "***")
}// Good - preserves error chain
return errs.Errorf("failed to process user %s: %w", userID, err)
// Avoid - loses error chain
return errs.New(fmt.Sprintf("failed: %s", err))// Use errs.New instead of errors.New
return errs.New("something failed")
// Use errs.Errorf instead of fmt.Errorf
return errs.Errorf("failed: %w", err)- Go version: Requires Go 1.13+ for error wrapping, Go 1.23+ for iterator support
- Error handling: Fully compatible with
errors.Is,errors.As,errors.Unwrap, anderrors.Join - Testing: Use with
testifyor any testing framework
- Zero-allocation error wrapping for functions with 0-10 parameters (using specialized functions)
- Efficient call stack capture using
runtime.Callers - Lazy error message formatting - only formats when
Error()is called - Configurable stack depth to balance detail vs memory usage
See the examples directory and godoc for more examples.
MIT License - see LICENSE file for details.
Contributions welcome! Please open an issue or submit a pull request.
- go-pretty - Pretty printing used for error parameter formatting