The errors.As function in Go is used to find and extract an error of a specific type from a chain of wrapped errors. This function is part of the errors package and is particularly useful when you need to access specific information or methods provided by a custom error type.
Syntax
func As(err error, target interface{}) 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: A pointer to a variable of the specific error type you’re trying to find. If the error in the chain matches the type, it will be assigned to this variable.
Returns:
- bool: Returns- trueif an error of the specified type is found in the error chain and assigns it to the target; otherwise, it returns- false.
Example Usage
Basic Example with Custom Error Type
This example demonstrates how to use errors.As to extract a custom error type from an error chain.
package main
import (
	"errors"
	"fmt"
)
type ValidationError struct {
	Field   string
	Message string
}
func (e *ValidationError) Error() string {
	return fmt.Sprintf("%s: %s", e.Field, e.Message)
}
func validate(input string) error {
	if input == "" {
		return &ValidationError{"Name", "cannot be empty"}
	}
	return nil
}
func main() {
	err := validate("")
	var validationErr *ValidationError
	if errors.As(err, &validationErr) {
		fmt.Printf("Validation Error - Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
	} else {
		fmt.Println("Error: an unknown error occurred.")
	}
}
Output:
Validation Error - Field: Name, Message: cannot be empty
Explanation:
- The validatefunction returns aValidationErrorif the input is invalid.
- The errors.Asfunction checks whether the returned error is of type*ValidationErrorand, if so, assigns it tovalidationErr.
- The extracted ValidationErroris then used to access specific fields.
Using errors.As with Wrapped Errors
The errors.As function is particularly useful when working with wrapped errors, where an error is wrapped with additional context using fmt.Errorf or similar functions.
Example
package main
import (
	"errors"
	"fmt"
)
type PermissionError struct {
	Operation string
}
func (e *PermissionError) Error() string {
	return fmt.Sprintf("permission denied: %s", e.Operation)
}
func openFile(filename string) error {
	// Simulate a permission error wrapped with additional context
	return fmt.Errorf("failed to open file %s: %w", filename, &PermissionError{"read"})
}
func main() {
	err := openFile("data.txt")
	var permErr *PermissionError
	if errors.As(err, &permErr) {
		fmt.Printf("Permission Error - Operation: %s\n", permErr.Operation)
	} else {
		fmt.Println("Error: an unknown error occurred.")
	}
}
Output:
Permission Error - Operation: read
Explanation:
- The openFilefunction simulates a permission error wrapped with additional context usingfmt.Errorfand the%wverb.
- The errors.Asfunction checks whether the error is of type*PermissionErrorand extracts it if present.
Combining errors.As with Standard Error Types
You can also use errors.As to extract standard error types such as *os.PathError.
Example
package main
import (
	"errors"
	"fmt"
	"os"
)
func main() {
	_, err := os.Open("nonexistent.txt")
	var pathErr *os.PathError
	if errors.As(err, &pathErr) {
		fmt.Printf("File Error - Path: %s, Op: %s\n", pathErr.Path, pathErr.Op)
	} else {
		fmt.Println("Error: an unknown error occurred.")
	}
}
Output:
File Error - Path: nonexistent.txt, Op: open
Explanation:
- The code attempts to open a nonexistent file, which generates an *os.PathError.
- The errors.Asfunction checks whether the error is of type*os.PathErrorand extracts the relevant information if it is.
Conclusion
The errors.As function in Go is used for error handling, especially when dealing with custom error types or when you need to extract specific information from a wrapped error. It allows you to work with errors in a more type-safe manner, enabling you to access fields and methods specific to a certain error type. By using errors.As, you can create more robust and maintainable error-handling logic, especially in complex systems where errors might be wrapped with additional context.