SkillAgentSearch skills...

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/Errors
About this skill

Quality Score

0/100

Category

Operations

Supported Platforms

Universal

README

Enhanced Error Handling for Go with Context, Stack Traces, Monitoring, and More

Go Reference Go Report Card License Benchmarks

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 for errors.Errorf("user %w not found", errors.New("bob"))
✓ added support for sequential chain execution ``

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

View on GitHub
GitHub Stars27
CategoryOperations
Updated2mo ago
Forks2

Languages

Go

Security Score

90/100

Audited on Jan 19, 2026

No findings