Errors
A production-grade error handling library for Go, offering zero-cost abstractions, stack traces, multi-error support, retries, and advanced monitoring through two complementary packages: errors (core) and errmgr (management).
Install / Use
/learn @olekukonko/ErrorsREADME
Enhanced Error Handling for Go with Context, Stack Traces, Monitoring, and More
A production-grade error handling library for Go, offering zero-cost abstractions, stack traces, multi-error support, retries, and advanced monitoring through two complementary packages: errors (core) and errmgr (management).
Features
errors Package (Core)
-
Performance Optimized
- Optional memory pooling (12 ns/op with pooling)
- Lazy stack trace collection (205 ns/op with stack)
- Small context optimization (≤4 items, 40 ns/op)
- Lock-free configuration reads
-
Debugging Tools
- Full stack traces with internal frame filtering
- Error wrapping and chaining
- Structured context attachment
- JSON serialization (662 ns/op)
-
Advanced Utilities
- Configurable retry mechanism
- Multi-error aggregation with sampling
- HTTP status code support
- Callback triggers for cleanup or side effects
errmgr Package (Management)
- Production Monitoring
- Error occurrence counting
- Threshold-based alerting
- Categorized metrics
- Predefined error templates
Installation
go get github.com/olekukonko/errors@latest
Package Overview
errors: Core error handling with creation, wrapping, context, stack traces, retries, and multi-error support.errmgr: Error management with templates, monitoring, and predefined errors for consistent application use.
[!NOTE]
✓ added support forerrors.Errorf("user %w not found", errors.New("bob"))
✓ added support forsequential chainexecution ``
Using the errors Package
Basic Error Creation
Simple Error
package main
import (
"fmt"
"github.com/olekukonko/errors"
)
func main() {
// Fast error with no stack trace
err := errors.New("connection failed")
fmt.Println(err) // "connection failed"
// Standard error, no allocation, same speed
stdErr := errors.Std("connection failed")
fmt.Println(stdErr) // "connection failed"
}
Formatted Error
// main.go
package main
import (
"fmt"
"github.com/olekukonko/errors"
)
func main() {
// Formatted error without stack trace
errNoWrap := errors.Newf("user %s not found", "bob")
fmt.Println(errNoWrap) // Output: "user bob not found"
// Standard formatted error, no fmt.Errorf needed (using own pkg)
stdErrNoWrap := errors.Stdf("user %s not found", "bob")
fmt.Println(stdErrNoWrap) // Output: "user bob not found"
// Added support for %w (compatible with fmt.Errorf output)
// errors.Errorf is alias of errors.Newf
errWrap := errors.Errorf("user %w not found", errors.New("bob"))
fmt.Println(errWrap) // Output: "user bob not found"
// Standard formatted error for comparison
stdErrWrap := fmt.Errorf("user %w not found", fmt.Errorf("bob"))
fmt.Println(stdErrWrap) // Output: "user bob not found"
}
Error with Stack Trace
package main
import (
"fmt"
"github.com/olekukonko/errors"
)
func main() {
// Create an error with stack trace using Trace
err := errors.Trace("critical issue")
fmt.Println(err) // Output: "critical issue"
fmt.Println(err.Stack()) // Output: e.g., ["main.go:15", "caller.go:42"]
// Convert basic error to traceable with WithStack
errS := errors.New("critical issue")
errS = errS.WithStack() // Add stack trace and update error
fmt.Println(errS) // Output: "critical issue"
fmt.Println(errS.Stack()) // Output: e.g., ["main.go:19", "caller.go:42"]
}
Named Error
package main
import (
"fmt"
"github.com/olekukonko/errors"
)
func main() {
// Create a named error with stack trace
err := errors.Named("InputError")
fmt.Println(err.Name()) // Output: "InputError"
fmt.Println(err) // Output: "InputError"
}
Adding Context
Basic Context
package main
import (
"fmt"
"github.com/olekukonko/errors"
)
func main() {
// Create an error with context
err := errors.New("processing failed").
With("id", "123").
With("attempt", 3).
With("retryable", true)
fmt.Println("Error:", err) // Output: "processing failed"
fmt.Println("Full context:", errors.Context(err)) // Output: map[id:123 attempt:3 retryable:true]
}
Context with Wrapped Standard Error
package main
import (
"fmt"
"github.com/olekukonko/errors"
)
func main() {
// Wrap a standard error and add context
err := errors.New("processing failed").
With("id", "123")
wrapped := fmt.Errorf("wrapped: %w", err)
fmt.Println("Wrapped error:", wrapped) // Output: "wrapped: processing failed"
fmt.Println("Direct context:", errors.Context(wrapped)) // Output: nil
// Convert to access context
e := errors.Convert(wrapped)
fmt.Println("Converted context:", e.Context()) // Output: map[id:123]
}
Adding Context to Standard Error
package main
import (
"fmt"
"github.com/olekukonko/errors"
)
func main() {
// Convert a standard error and add context
stdErr := fmt.Errorf("standard error")
converted := errors.Convert(stdErr).
With("source", "legacy").
With("severity", "high")
fmt.Println("Message:", converted.Error()) // Output: "standard error"
fmt.Println("Context:", converted.Context()) // Output: map[source:legacy severity:high]
}
Complex Context
package main
import (
"fmt"
"github.com/olekukonko/errors"
)
func main() {
// Create an error with complex context
err := errors.New("database operation failed").
With("query", "SELECT * FROM users").
With("params", map[string]interface{}{
"limit": 100,
"offset": 0,
}).
With("duration_ms", 45.2)
fmt.Println("Complex error context:")
for k, v := range errors.Context(err) {
fmt.Printf("%s: %v (%T)\n", k, v, v)
}
// Output:
// query: SELECT * FROM users (string)
// params: map[limit:100 offset:0] (map[string]interface {})
// duration_ms: 45.2 (float64)
}
Stack Traces
Adding Stack to Any Error
package main
import (
"fmt"
"github.com/olekukonko/errors"
)
func main() {
// Add stack trace to a standard error
err := fmt.Errorf("basic error")
enhanced := errors.WithStack(err)
fmt.Println("Error with stack:")
fmt.Println("Message:", enhanced.Error()) // Output: "basic error"
fmt.Println("Stack:", enhanced.Stack()) // Output: e.g., "main.go:15"
}
Chaining with Stack
package main
import (
"fmt"
"github.com/olekukonko/errors"
"time"
)
func main() {
// Create an enhanced error and add stack/context
err := errors.New("validation error").
With("field", "email")
stackErr := errors.WithStack(err).
With("timestamp", time.Now()).
WithCode(500)
fmt.Println("Message:", stackErr.Error()) // Output: "validation error"
fmt.Println("Context:", stackErr.Context()) // Output: map[field:email timestamp:...]
fmt.Println("Stack:")
for _, frame := range stackErr.Stack() {
fmt.Println(frame)
}
}
Stack Traces with WithStack()
package main
import (
"fmt"
"github.com/olekukonko/errors"
"math/rand"
"time"
)
func basicFunc() error {
return fmt.Errorf("basic error")
}
func enhancedFunc() *errors.Error {
return errors.New("enhanced error")
}
func main() {
// 1. Package-level WithStack - works with ANY error type
err1 := basicFunc()
enhanced1 := errors.WithStack(err1) // Handles basic errors
fmt.Println("Package-level WithStack:")
fmt.Println(enhanced1.Stack())
// 2. Method-style WithStack - only for *errors.Error
err2 := enhancedFunc()
enhanced2 := err2.WithStack() // More natural chaining
fmt.Println("\nMethod-style WithStack:")
fmt.Println(enhanced2.Stack())
// 3. Combined usage in real-world scenario
result := processData()
if result != nil {
// Use package-level when type is unknown
stackErr := errors.WithStack(result)
// Then use method-style for chaining
finalErr := stackErr.
With("timestamp", time.Now()).
WithCode(500)
fmt.Println("\nCombined Usage:")
fmt.Println("Message:", finalErr.Error())
fmt.Println("Context:", finalErr.Context())
fmt.Println("Stack:")
for _, frame := range finalErr.Stack() {
fmt.Println(frame)
}
}
}
func processData() error {
// Could return either basic or enhanced error
if rand.Intn(2) == 0 {
return fmt.Errorf("database error")
}
return errors.New("validation error").With("field", "email")
}
Error Wrapping and Chaining
Basic Wrapping
package main
import (
"fmt"
"github.com/olekukonko/errors"
)
func main() {
// Wrap an error with additional context
lowErr := errors.New("low-level failure")
highErr := errors.Wrapf(lowErr, "high-level operation failed: %s", "details")
fmt.Println(highErr) // Output: "high-level operation failed: details: low-level failure"
fmt.Println(errors.Unwrap(highErr)) // Output: "low-level failure"
}
Walking Error Chain
package main
import (
"fmt"
"github.com/olekukonko/errors"
)
func main() {
// Create a chained error
dbErr := errors.New("connection timeout").
With("server", "db01.prod")
bizErr := errors.New("failed to process user 12345").
With("user_id", "12345").
Wrap(dbErr)
apiErr := errors.New("API request failed").
WithCode(500).
Wrap(bizErr)
// Walk the error chain
fmt.Println("Error Chain:")
for i, e := range errors.UnwrapAll(apiErr) {
fmt.Printf("%d. %s\n", i+1, e)
}
// Output:
// 1. API request failed
// 2. failed to process user 12345
// 3. connection timeout
}
Type Assertions
Using Is
package main
import (
"fmt"
"github.com/olekukonko/errors"
)
func main(
Related Skills
tmux
351.4kRemote-control tmux sessions for interactive CLIs by sending keystrokes and scraping pane output.
diffs
351.4kUse the diffs tool to produce real, shareable diffs (viewer URL, file artifact, or both) instead of manual edit summaries.
blogwatcher
351.4kMonitor blogs and RSS/Atom feeds for updates using the blogwatcher CLI.
github-trending
Multi-agent orchestration system for infrastructure monitoring, incident response, and load testing with autonomous AI agents
