The errors.Unwrap function in Go is used to retrieve the next error in a chain of wrapped errors. This function is part of the errors package and is particularly useful when you need to access the underlying error that has been wrapped with additional context.
Syntax
func Unwrap(err error) error
Parameters:
err: The error from which to retrieve the underlying error. This error might have been wrapped with additional context using functions likefmt.Errorf.
Returns:
error: The next error in the chain if it exists; otherwise, it returnsnil.
Example Usage
Basic Example
This example demonstrates how to use errors.Unwrap to retrieve the underlying error from a wrapped error.
package main
import (
"errors"
"fmt"
)
func main() {
originalErr := errors.New("original error")
wrappedErr := fmt.Errorf("an error occurred: %w", originalErr)
unwrappedErr := errors.Unwrap(wrappedErr)
fmt.Println("Wrapped Error:", wrappedErr)
fmt.Println("Unwrapped Error:", unwrappedErr)
}
Output:
Wrapped Error: an error occurred: original error
Unwrapped Error: original error
Explanation:
- The
errors.Newfunction creates anoriginalErr. - The
fmt.Errorffunction wraps theoriginalErrwith additional context. - The
errors.Unwrapfunction retrieves theoriginalErrfrom the wrapped error.
Working with Multiple Levels of Wrapping
The errors.Unwrap function can be used to step through multiple levels of wrapped errors.
Example
package main
import (
"errors"
"fmt"
)
func main() {
level1Err := errors.New("level 1 error")
level2Err := fmt.Errorf("level 2 error: %w", level1Err)
level3Err := fmt.Errorf("level 3 error: %w", level2Err)
fmt.Println("Level 3 Error:", level3Err)
// Unwrap level 3 to level 2
level2 := errors.Unwrap(level3Err)
fmt.Println("Level 2 Error:", level2)
// Unwrap level 2 to level 1
level1 := errors.Unwrap(level2)
fmt.Println("Level 1 Error:", level1)
}
Output:
Level 3 Error: level 3 error: level 2 error: level 1 error
Level 2 Error: level 2 error: level 1 error
Level 1 Error: level 1 error
Explanation:
- The errors are wrapped at different levels, with each level adding more context to the error.
- The
errors.Unwrapfunction is used to step through the error chain, retrieving each underlying error.
Using errors.Unwrap in Custom Error Types
You can implement custom error types that support unwrapping by implementing the Unwrap method.
Example
package main
import (
"errors"
"fmt"
)
type MyError struct {
Msg string
Err error
}
func (e *MyError) Error() string {
return fmt.Sprintf("%s: %v", e.Msg, e.Err)
}
func (e *MyError) Unwrap() error {
return e.Err
}
func main() {
originalErr := errors.New("original error")
myErr := &MyError{Msg: "my custom error", Err: originalErr}
unwrappedErr := errors.Unwrap(myErr)
fmt.Println("My Error:", myErr)
fmt.Println("Unwrapped Error:", unwrappedErr)
}
Output:
My Error: my custom error: original error
Unwrapped Error: original error
Explanation:
- The
MyErrortype implements theErrorandUnwrapmethods, allowing it to be unwrapped usingerrors.Unwrap. - The
errors.Unwrapfunction retrieves the underlyingoriginalErrfromMyError.
Checking for a Specific Error in a Chain
The errors.Unwrap function can be used in a loop to iterate through an error chain and check for a specific error.
Example
package main
import (
"errors"
"fmt"
)
var ErrPermission = errors.New("permission denied")
func main() {
originalErr := ErrPermission
wrappedErr := fmt.Errorf("operation failed: %w", originalErr)
moreWrappedErr := fmt.Errorf("additional context: %w", wrappedErr)
err := moreWrappedErr
for err != nil {
if errors.Is(err, ErrPermission) {
fmt.Println("Found permission denied error.")
break
}
err = errors.Unwrap(err)
}
}
Output:
Found permission denied error.
Explanation:
- The code wraps the
ErrPermissionerror multiple times. - A loop is used to unwrap the errors and check if any of them match
ErrPermission.
Conclusion
The errors.Unwrap function in Go is used for working with wrapped errors, allowing you to access the underlying error that has been wrapped with additional context. This function is especially helpful in scenarios where you need to dig deeper into the error chain to understand the root cause of an error. By using errors.Unwrap, you can create more detailed and informative error-handling logic, making your Go applications more robust and easier to debug.