Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@
## API and Compatibility Notes
- Do not introduce new usage of deprecated `Cause()`; prefer `errors.Is`/`errors.As` compatible flows and `Unwrap`/`Unwraps`.
- Keep `errs.Join` behavior stable: ignore nil arguments and return nil when all arguments are nil.
- Keep thread-safety semantics clear: `errs.Errors` is container-safe, but contained error values (including `errs.Error`) are not guaranteed goroutine-safe.
- Treat changes to exported symbols, function signatures, and observable error formatting behavior as potentially breaking.
- Error string and JSON formatting are validated by tests; when output behavior changes, update README examples and test expectations in the same change.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ For multiple causes, it returns all causes as a slice.
- If `WithCause` is given multiple times, the last cause is used
- `errs.Join(...)` ignores `nil` arguments and returns `nil` if all arguments are `nil`

### Concurrency notes

- `errs.Errors` is goroutine-safe for container operations such as `Add`, `ErrorOrNil`, and `Unwrap`.
- Errors stored in `errs.Errors` are not guaranteed to be goroutine-safe.
- `errs.Error` has mutable state (`Context` map), so avoid concurrent mutation while formatting or encoding the same instance.

### Create new error instance with cause

```go
Expand Down
5 changes: 4 additions & 1 deletion errlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import (
)

// Errors is multiple error instance.
//
// Errors protects concurrent access to the container itself, but each contained
// error may still be non-thread-safe.
type Errors struct {
mu sync.RWMutex
errs []error
Expand Down Expand Up @@ -167,7 +170,7 @@ func (es *Errors) Unwrap() []error {
if len(es.errs) == 0 {
return nil
}
cpy := make([]error, len(es.errs), cap(es.errs))
cpy := make([]error, len(es.errs))
copy(cpy, es.errs)
return cpy
}
Expand Down
3 changes: 3 additions & 0 deletions errs.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ const (

// Error type is a implementation of error interface.
// This type is for wrapping cause error instance.
//
// Error is not goroutine-safe. Its Context field is a mutable map and can be
// modified by SetContext or direct field access.
type Error struct {
wrapFlag bool
Err error
Expand Down
4 changes: 2 additions & 2 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ func ExampleErrors() {
}()
}
wg.Wait()
fmt.Println("error ount =", len(errlist.Unwrap()))
fmt.Println("error count =", len(errlist.Unwrap()))
// Output:
// error ount = 100000
// error count = 100000
}

/* Copyright 2019-2023 Spiegel
Expand Down
Loading