The errors.Is function in Go is used to determine whether a specific error is present in a chain of wrapped errors. This function is part of the errors package and is particularly useful when you need to check if an error is equivalent to a specific target error, even if the error has been wrapped with additional context.
Syntax
func Is(err, target error) bool
Parameters:
- err: The error to be checked. This can be a simple error or an error that has been wrapped with additional context.
- target: The specific error you want to check for in the error chain.
Returns:
- bool: Returns- trueif the target error is found in the error chain; otherwise, it returns- false.
Example Usage
Basic Example
This example demonstrates how to use errors.Is to check if a given error is equivalent to a target error.
package main
import (
	"errors"
	"fmt"
)
var ErrNotFound = errors.New("item not found")
func findItem(id int) error {
	// Simulate an item not found situation
	return ErrNotFound
}
func main() {
	err := findItem(1)
	if errors.Is(err, ErrNotFound) {
		fmt.Println("Error: the item was not found.")
	} else {
		fmt.Println("Error: an unknown error occurred.")
	}
}
Output:
Error: the item was not found.
Using errors.Is with Wrapped Errors
The errors.Is function is particularly useful when dealing with wrapped errors, where an error is wrapped with additional context using fmt.Errorf or similar functions.
Example
package main
import (
	"errors"
	"fmt"
)
var ErrPermission = errors.New("permission denied")
func openFile(filename string) error {
	// Simulate a permission error wrapped with additional context
	return fmt.Errorf("cannot open file %s: %w", filename, ErrPermission)
}
func main() {
	err := openFile("data.txt")
	if errors.Is(err, ErrPermission) {
		fmt.Println("Error: permission denied.")
	} else {
		fmt.Println("Error: an unknown error occurred.")
	}
}
Output:
Error: permission denied.
Explanation:
- The openFilefunction simulates a permission error, wrapping it with additional context usingfmt.Errorfand the%wverb.
- The errors.Isfunction checks if the originalErrPermissionis part of the error chain.
Combining errors.Is with Custom Error Types
You can also use errors.Is to check for custom error types by defining them as variables.
Example
package main
import (
	"errors"
	"fmt"
)
type ValidationError struct {
	Message string
}
func (e *ValidationError) Error() string {
	return e.Message
}
var ErrInvalidInput = &ValidationError{"invalid input"}
func validate(input string) error {
	if input == "" {
		return fmt.Errorf("validation failed: %w", ErrInvalidInput)
	}
	return nil
}
func main() {
	err := validate("")
	if errors.Is(err, ErrInvalidInput) {
		fmt.Println("Error: invalid input provided.")
	} else {
		fmt.Println("Error: an unknown error occurred.")
	}
}
Output:
Error: invalid input provided.
Explanation:
- The ValidationErrortype is defined with an error message.
- The validatefunction checks for invalid input and wraps the custom errorErrInvalidInput.
- The errors.Isfunction successfully identifies the wrapped custom error.
Conclusion
The errors.Is function in Go is used for error handling, particularly when working with wrapped errors. It allows you to check if a specific error is present in the chain of errors, making it easier to handle and respond to errors in your applications. By using errors.Is, you can create more robust and maintainable error-handling logic, especially in complex systems where errors might be wrapped with additional context.