Custom Errors
Implementing the error interface with a struct to carry structured context callers can extract.
Any type that implements Error() string satisfies the error interface. A custom error struct lets you attach structured context - HTTP status codes, resource IDs, error codes - that callers extract with errors.As without parsing strings.
Define a struct with the fields you need, implement Error() string, and return the concrete type as an error interface from public APIs.
package main
import (
"errors"
"fmt"
)
type RequestError struct {
StatusCode int
Method string
URL string
}
func (e *RequestError) Error() string {
return fmt.Sprintf("%s %s: status %d", e.Method, e.URL, e.StatusCode)
}
func fetchData(url string) error {
// simulated HTTP call returning 404
return &RequestError{
StatusCode: 404,
Method: "GET",
URL: url,
}
}
func main() {
err := fetchData("/api/users/99")
if err != nil {
fmt.Println(err)
var re *RequestError
if errors.As(err, &re) {
fmt.Printf("HTTP %d on %s %s\n", re.StatusCode, re.Method, re.URL)
}
}
}You can also implement Unwrap() error to participate in error chain inspection:
type DBError struct {
Op string
Err error // underlying cause
}
func (e *DBError) Error() string { return fmt.Sprintf("db %s: %v", e.Op, e.Err) }
func (e *DBError) Unwrap() error { return e.Err }
var ErrConnFailed = errors.New("connection failed")
err := &DBError{Op: "query", Err: ErrConnFailed}
fmt.Println(errors.Is(err, ErrConnFailed)) // true - Unwrap lets Is walk the chainIn production
Return the concrete error type as an error interface from public functions - returning *RequestError directly leaks implementation details and breaks errors.As chains when callers use the interface. A custom error type lets callers extract structured context (HTTP status, error code, resource ID) without string parsing. Accept error in function signatures, not concrete types; code that receives an error is decoupled from the specific implementation. Implement Unwrap() error when your custom error wraps another error so errors.Is and errors.As can traverse the full chain.
Enjoyed this? Get more essays on software craft delivered to your inbox.
Subscribe free