Errors as Values
Overview
Go treats errors as values, not exceptions. Functions return errors alongside results, making error handling explicit and visible.
The error Interface
type error interface {
Error() string
}Returning Errors
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
result, err := divide(10, 0)
if err != nil {
log.Fatal(err)
}Creating Errors
import "errors"
// Simple error
err := errors.New("something went wrong")
// Formatted error
err := fmt.Errorf("failed to open %s: %v", filename, originalErr)Error Handling Patterns
Check Immediately
result, err := doSomething()
if err != nil {
return err
}
// Use resultEarly Return
func process() error {
data, err := fetch()
if err != nil {
return err
}
result, err := transform(data)
if err != nil {
return err
}
return save(result)
}Add Context
data, err := readFile(path)
if err != nil {
return fmt.Errorf("loading config: %w", err)
}Custom Error Types
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("%s: %s", e.Field, e.Message)
}
func validate(u User) error {
if u.Name == "" {
return &ValidationError{Field: "name", Message: "required"}
}
return nil
}Sentinel Errors
var ErrNotFound = errors.New("not found")
var ErrPermission = errors.New("permission denied")
func find(id int) (*User, error) {
if !exists(id) {
return nil, ErrNotFound
}
// ...
}
// Check
if err == ErrNotFound {
// Handle not found
}Summary
| Pattern | Usage |
|---|---|
errors.New() |
Simple error |
fmt.Errorf() |
Formatted error |
| Custom type | Structured error data |
| Sentinel | Known error values |