Custom Errors
Implementing the error interface with a struct to carry structured context callers can extract.
A custom error is a type that implements Error() string. Use a struct when callers need structured details such as an operation, resource, or status code.
Return the custom type as an error. Callers use errors.As to recover its fields, and Unwrap exposes an underlying cause.
package main
import (
"errors"
"fmt"
)
var ErrUnavailable = errors.New("service unavailable")
type RequestError struct {
Method string
URL string
Cause error
}
func (e *RequestError) Error() string {
return fmt.Sprintf("%s %s: %v", e.Method, e.URL, e.Cause)
}
func (e *RequestError) Unwrap() error {
return e.Cause
}
func fetch(url string) error {
return &RequestError{Method: "GET", URL: url, Cause: ErrUnavailable}
}
func main() {
err := fetch("/users/99")
var requestErr *RequestError
if errors.As(err, &requestErr) {
fmt.Println(requestErr.Method, requestErr.URL)
}
fmt.Println(errors.Is(err, ErrUnavailable))
}In production
An error return keeps a function's contract decoupled from one implementation, while callers can still inspect details with errors.As. Implement Unwrap() error when the custom error carries a cause. Treat error text as human-readable output, not a stable machine-readable format.
Enjoyed this? Get more software craft delivered to your inbox.