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
22 changes: 15 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,17 +212,25 @@ These create `PanicError` instances with stack traces.

Special error types for network-style temporary and timeout conditions:

* `TemporaryError` type - implements `Temporary() bool`
* `NewTemporaryError(err)` - wrap error as temporary
* `NewTimeoutError(err)` - wrap error as timeout
* `IsTemporary(err)` / `CheckIsTemporary(err)` - test if error is temporary
* `IsTimeout(err)` / `CheckIsTimeout(err)` - test if error is timeout
* `TemporaryError` type - implements `Temporary() bool` and `IsTemporary() bool`
interfaces for marking recoverable errors.
* `NewTemporaryError(err)` - wrap error as temporary condition.
* `NewTimeoutError(err)` - wrap error as timeout condition with both temporary
and timeout properties.
* `IsTemporary(err)` - recursively test if error chain contains temporary
condition via `Temporary()` or `IsTemporary()` methods.
* `CheckIsTemporary(err)` - test single error for temporary condition without
unwrapping chain, returns (is, known) tuple.
* `IsTimeout(err)` - recursively test if error chain contains timeout
condition via `Timeout()` or `IsTimeout()` methods.
* `CheckIsTimeout(err)` - test single error for timeout condition without
unwrapping chain, returns (is, known) tuple.

### Error Testing and Utilities

* `IsError[T](err)` / `IsErrorFn[T](err, fn)` / `IsErrorFn2[T](err, fn)` -
type-safe error testing
* `CoalesceError(errs...)` - return first non-nil error
type-safe error testing with generic constraints and custom checker functions.
* `CoalesceError(errs...)` - return first non-nil error from argument list.

## Stack Tracing

Expand Down
72 changes: 64 additions & 8 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,21 @@ func IsErrorFn2(check func(error) (bool, bool), errs ...error) (is, known bool)
return false, false
}

// CheckIsTemporary tests an error for Temporary(), IsTemporary(),
// Timeout() and IsTimeout() without unwrapping.
// CheckIsTemporary tests an error for temporary conditions without unwrapping.
// It checks if the error implements Temporary() bool or IsTemporary() bool
// interfaces directly, without traversing wrapped error chains.
//
// The function examines the error in the following priority order:
// - Temporary() bool interface (legacy net.Error style)
// - IsTemporary() bool interface (modern style)
// - Falls back to CheckIsTimeout for timeout-based temporary errors
//
// Returns:
// - is: true if the error indicates a temporary condition
// - known: true if the error type implements a recognized interface
//
// For nil errors, returns (false, true) indicating definitively not temporary.
// For errors with no recognized interface, returns result from CheckIsTimeout.
func CheckIsTemporary(err error) (is, known bool) {
switch e := err.(type) {
case nil:
Expand All @@ -309,15 +322,44 @@ func CheckIsTemporary(err error) (is, known bool) {
}
}

// IsTemporary tests an error for Temporary(), IsTemporary(),
// Timeout() and IsTimeout() recursively.
// IsTemporary tests an error chain for temporary conditions recursively.
// It traverses wrapped error chains using IsErrorFn2 to find any error
// that implements temporary condition interfaces.
//
// This function provides comprehensive temporary error detection by:
// - Checking each error in the unwrapping chain via CheckIsTemporary
// - Following both Unwrap() error and Unwrap() []error patterns
// - Detecting legacy net.Error.Temporary() implementations
// - Detecting modern IsTemporary() bool implementations
// - Detecting timeout errors (which are also considered temporary)
//
// Returns true if any error in the chain indicates a temporary condition.
// Returns false for nil errors or chains with no temporary indicators.
//
// Use this function when you need to determine if an operation should be
// retried based on the error's temporary nature.
func IsTemporary(err error) bool {
is, _ := IsErrorFn2(CheckIsTemporary, err)
return is
}

// CheckIsTimeout tests an error for Timeout() and IsTimeout()
// without unwrapping.
// CheckIsTimeout tests an error for timeout conditions without unwrapping.
// It checks if the error implements Timeout() bool or IsTimeout() bool
// interfaces directly, without traversing wrapped error chains.
//
// The function examines the error in the following priority order:
// - Timeout() bool interface (legacy net.Error style)
// - IsTimeout() bool interface (modern style)
//
// Returns:
// - is: true if the error indicates a timeout condition
// - known: true if the error type implements a recognized timeout interface
//
// For nil errors, returns (false, true) indicating definitively not a timeout.
// For errors with no recognized timeout interface, returns (false, false).
//
// Note that timeout errors are typically also considered temporary conditions,
// but this function specifically tests for timeout semantics only.
func CheckIsTimeout(err error) (is, known bool) {
switch e := err.(type) {
case nil:
Expand All @@ -335,8 +377,22 @@ func CheckIsTimeout(err error) (is, known bool) {
}
}

// IsTimeout tests an error for Timeout() and IsTimeout()
// recursively.
// IsTimeout tests an error chain for timeout conditions recursively.
// It traverses wrapped error chains using IsErrorFn2 to find any error
// that implements timeout condition interfaces.
//
// This function provides comprehensive timeout error detection by:
// - Checking each error in the unwrapping chain via CheckIsTimeout
// - Following both Unwrap() error and Unwrap() []error patterns
// - Detecting legacy net.Error.Timeout() implementations
// - Detecting modern IsTimeout() bool implementations
//
// Returns true if any error in the chain indicates a timeout condition.
// Returns false for nil errors or chains with no timeout indicators.
//
// Use this function when you need to distinguish timeout errors from
// other types of temporary errors for specialized retry logic or
// timeout-specific error handling.
func IsTimeout(err error) bool {
is, _ := IsErrorFn2(CheckIsTimeout, err)
return is
Expand Down
Loading