Since Go 1.13, we have new helpful ways to find out the type of error, even if we use error wrapping. If we want to check if a given error matches another specific error, we need to use Is() function from the errors package. If we are interested in whether the error is of a given type, we should call the As() function.
Is() function
In the example below, we can see that the function validateInput returns an error for badInput. This error is ErrBadInput wrapped in an error created by fmt.Errorf(). Using the Is(err, target error) bool function, we can detect the ErrBadInput even if it is wrapped since this function checks if any error in the chain of wrapped errors matches the target. Therefore, this form should be preferable to comparison if err == ErrBadInput.
package main
import (
"errors"
"fmt"
)
const badInput = "abc"
var ErrBadInput = errors.New("bad input")
func validateInput(input string) error {
if input == badInput {
return fmt.Errorf("validateInput: %w", ErrBadInput)
}
return nil
}
func main() {
input := badInput
err := validateInput(input)
if errors.Is(err, ErrBadInput) {
fmt.Println("bad input error")
}
}
Output:
bad input errorAs() function
Similar to Is(), the As(err error, target interface{}) bool checks if any error in the chain of wrapped errors matches the target. The difference is that this function checks whether the error has a specific type, unlike the Is(), which examines if it is a particular error object. Because As considers the whole chain of errors, it should be preferable to the type assertion if e, ok := err.(*BadInputError); ok.
targetargument of theAs(err error, target interface{}) boolfunction should be a pointer to the error type, which in this case is*BadInputError
package main
import (
"errors"
"fmt"
)
const badInput = "abc"
type BadInputError struct {
input string
}
func (e *BadInputError) Error() string {
return fmt.Sprintf("bad input: %s", e.input)
}
func validateInput(input string) error {
if input == badInput {
return fmt.Errorf("validateInput: %w", &BadInputError{input: input})
}
return nil
}
func main() {
input := badInput
err := validateInput(input)
var badInputErr *BadInputError
if errors.As(err, &badInputErr) {
fmt.Printf("bad input error occured: %s\n", badInputErr)
}
}
Output:
bad input error occured: bad input: abc