Help us shape the future of Go! Take the 2026 Go Developer Survey

errbuf

package module
v1.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 13, 2026 License: MIT Imports: 5 Imported by: 0

README

errbuf

Go Reference Go Report Card

errbuf is optimized, thread-safe error buffer for Go. It allows you to concurrently aggregate multiple errors and format them efficiently with zero allocation overhead on the fast paths.

Installation

go get github.com/emar-kar/errbuf

Usage

Basic Usage

Create an error buffer, safely add errors from multiple goroutines, and evaluate the final result.

package main

import (
	"errors"
	"fmt"
	"sync"
	
	"github.com/emar-kar/errbuf"
)

func main() {
	buf := errbuf.New()

	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			// Safely add errors concurrently.
			buf.Add(fmt.Errorf("error from worker %d", id))
		}(i)
	}
	
	wg.Wait()

	// Conditionally check if any errors were recorded.
	if err := buf.Err(); err != nil {
		fmt.Printf("Encountered errors: %v\n", err)
	}
}
Memory Optimized Batching

If you run repeating batch tasks, use Clear() to instantly empty the buffer while keeping the underlying array capacity initialized. This guarantees exactly 0 dynamic append allocations, perfectly maximizing runtime speed.

buf := errbuf.New()
buf.Grow(100) // Optionally pre-allocate exactly 100 slots

for batch := 0; batch < 1000; batch++ {
	errs := processBatch(batch)
	buf.Add(errs...)
	
	if err := buf.Err(); err != nil {
		log.Println("Batch failed:", err)
	}
	
	buf.Clear() // O(1) allocation clear.
}
Custom Formatting

BufferedError natively implements fmt.Formatter so you can format errors cleanly.

buf := errbuf.New()
buf.Add(errors.New("connection reset"), errors.New("timeout"))

// Standard line separated by semicolons.
fmt.Printf("%s\n", buf) 
// Output: "connection reset; timeout"

// Multiline formatting.
fmt.Printf("%v\n", buf)
// Output: 
// connection reset
// timeout

// Full inspection.
fmt.Printf("%+v\n", buf)
// Output: BufferedError{errors:[connection reset timeout]}
errors.Is and errors.As support

You can query deeply into the buffer without needing to manually unroll it.

var ErrNotFound = errors.New("not found")

buf := errbuf.New()
buf.Add(errors.New("database disconnected"), ErrNotFound)

// Checks all errors inside the buffer for the target
if errors.Is(buf, ErrNotFound) {
	fmt.Println("Item was not found!")
}

Benchmarks

The package is deeply tuned for performance against internal micro-benchmarks:

BenchmarkBufferedErrorAddSlice1000-10               3894      30914 ns/op       12293 B/op         1 allocs/op
BenchmarkBufferedErrorAddSlice1000All-10            8650      14219 ns/op       12294 B/op         1 allocs/op
BenchmarkBufferedErrorAdd1-10                    2511114         47.29 ns/op        0 B/op         0 allocs/op
BenchmarkBufferedErrorAddParallel-10              950526        144.6 ns/op       104 B/op         0 allocs/op
BenchmarkBuffereErrorMultiLine-10                   3517      33364 ns/op       12346 B/op         1 allocs/op

License

MIT License

Documentation

Overview

Package errbuf provides a thread-safe buffer for accumulating multiple errors. It implements the standard error interface and supports custom formatting for single-line or multi-line display of the aggregated errors.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BufferedError

type BufferedError struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

BufferedError represents an aggregated collection of errors. It is safe for concurrent use by multiple goroutines. The zero value is an empty, ready-to-use error buffer.

func New added in v1.2.0

func New() *BufferedError

New creates and returns an empty, ready-to-use BufferedError.

func NewFromError added in v1.2.0

func NewFromError(err error) *BufferedError

NewFromError creates a new BufferedError initialized with the given error. If the given err is nil, it returns an empty BufferedError.

func (*BufferedError) Add

func (b *BufferedError) Add(errs ...error)

Add appends one or more errors to the buffer. Nil errors are ignored and will not be added to the buffer.

func (*BufferedError) As added in v1.3.0

func (b *BufferedError) As(target any) bool

As finds the first error in b's buffer that matches target, and if one is found, sets target to that error value and returns true. Otherwise, it returns false.

func (*BufferedError) Clear added in v1.2.0

func (b *BufferedError) Clear()

Clear empties the internal buffer. To avoid costly reallocations, the underlying backing array is retained. Elements are nil'd out so the garbage collector can reclaim the error objects safely.

func (*BufferedError) Err

func (b *BufferedError) Err() error

Err returns the BufferedError itself if it contains one or more errors. If the buffer is empty, it returns nil. This is useful for conditional error returning like: `if err := buf.Err(); err != nil { return err }`.

func (*BufferedError) Error

func (b *BufferedError) Error() string

Error returns a string representation of all buffered errors. If the buffer is empty, it returns an empty string. If the buffer contains exactly one error, it returns that error's string representation. For two or more errors, they are joined by a semicolon separator ("; ").

func (*BufferedError) Format added in v1.2.0

func (b *BufferedError) Format(f fmt.State, verb rune)

Format implements the fmt.Formatter interface to support custom error formatting.

The following format verbs are supported:

%s         Prints errors on one line separated by semicolons (e.g. "err1; err2").
%v         Prints errors separated by newlines (multiline).
%+v        Prints the raw internal representation: "BufferedError{errors:[...]}".

func (*BufferedError) Grow added in v1.2.0

func (b *BufferedError) Grow(n int)

Grow increases the internal slice capacity to accommodate n errors. If the internal capacity is already greater than or equal to n, this is a no-op. This is useful for optimizing allocations when the number of errors to be added is known in advance.

func (*BufferedError) Is added in v1.3.0

func (b *BufferedError) Is(target error) bool

Is reports whether any error in b's buffer matches target.

func (*BufferedError) Unwrap

func (b *BufferedError) Unwrap() []error

Unwrap returns a shallow copy of the underlying slice of accumulated errors. Modifications to the returned slice will not affect the buffer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL