58 lines
1.8 KiB
Markdown
58 lines
1.8 KiB
Markdown
# ADR-0008: Error Handling Strategy
|
|
|
|
## Status
|
|
Accepted
|
|
|
|
## Context
|
|
Go's error handling philosophy requires explicit error checking. We need a consistent approach for:
|
|
- Error creation and wrapping
|
|
- Error propagation
|
|
- Error classification (domain vs infrastructure)
|
|
- Error reporting (logging, monitoring)
|
|
- HTTP error responses
|
|
|
|
## Decision
|
|
Adopt a **wrapped error pattern** with **structured error types**:
|
|
|
|
1. **Error Wrapping**: Use `fmt.Errorf("context: %w", err)` for error wrapping
|
|
2. **Error Types**: Define custom error types for domain errors
|
|
3. **Error Classification**: Distinguish between:
|
|
- Domain errors (business logic failures)
|
|
- Infrastructure errors (external system failures)
|
|
- Validation errors (input validation failures)
|
|
4. **Error Context**: Always wrap errors with context about where they occurred
|
|
|
|
**Rationale:**
|
|
- Follows Go 1.13+ error wrapping best practices
|
|
- Enables error inspection with `errors.Is()` and `errors.As()`
|
|
- Maintains error chains for debugging
|
|
- Allows structured error handling
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
- Full error traceability through call stack
|
|
- Can inspect and handle specific error types
|
|
- Better debugging with error context
|
|
- Aligns with Go best practices
|
|
|
|
### Negative
|
|
- Requires discipline to wrap errors consistently
|
|
- Can be verbose in some cases
|
|
|
|
### Implementation Notes
|
|
- Always wrap errors: `return nil, fmt.Errorf("failed to load config: %w", err)`
|
|
- Create error types for domain errors:
|
|
```go
|
|
type ConfigError struct {
|
|
Key string
|
|
Cause error
|
|
}
|
|
func (e *ConfigError) Error() string { ... }
|
|
func (e *ConfigError) Unwrap() error { return e.Cause }
|
|
```
|
|
- Use `errors.Is()` and `errors.As()` for error checking
|
|
- Log errors with context before returning
|
|
- Map domain errors to HTTP status codes in handlers
|
|
|