Error Best Practices
Fundamental Error Handling Principles
1. Always Check Errors
func processData(data []byte) error {
// Bad practice
// file, _ := os.Create("output.txt")
// Good practice
file, err := os.Create("output.txt")
if err != nil {
return fmt.Errorf("failed to create file: %w", err)
}
defer file.Close()
}
Error Wrapping and Context
2. Provide Meaningful Error Context
func fetchUserData(userID int) (*User, error) {
user, err := database.GetUser(userID)
if err != nil {
return nil, fmt.Errorf("failed to retrieve user %d: %w", userID, err)
}
return user, nil
}
Error Handling Strategies
3. Use Custom Error Types
type ValidationError struct {
Field string
Value interface{}
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation error: %s has invalid value %v", e.Field, e.Value)
}
func validateUser(user *User) error {
if user.Age < 0 {
return &ValidationError{
Field: "Age",
Value: user.Age,
}
}
return nil
}
Error Flow Management
graph TD
A[Receive Error] --> B{Is Error Recoverable?}
B -->|Yes| C[Handle/Retry]
B -->|No| D[Log and Propagate]
C --> E[Continue Execution]
D --> F[Return Error]
Error Handling Patterns
Pattern |
Description |
Example Use Case |
Early Return |
Handle errors immediately |
Input validation |
Error Wrapping |
Add context to errors |
Complex operations |
Sentinel Errors |
Predefined error types |
Specific error conditions |
Advanced Error Handling
4. Avoid Silent Failures
func processItems(items []string) error {
var errs []error
for _, item := range items {
if err := processItem(item); err != nil {
errs = append(errs, err)
}
}
if len(errs) > 0 {
return fmt.Errorf("multiple errors occurred: %v", errs)
}
return nil
}
Panic and Recovery
5. Use Panic Sparingly
func safeExecute(fn func()) (recovered interface{}) {
defer func() {
recovered = recover()
}()
fn()
return nil
}
Logging and Monitoring
6. Implement Comprehensive Logging
func criticalOperation() error {
err := performOperation()
if err != nil {
log.WithFields(log.Fields{
"error": err,
"timestamp": time.Now(),
}).Error("Operation failed")
return err
}
return nil
}
Key Recommendations
- Always handle errors explicitly
- Provide rich error context
- Use custom error types when appropriate
- Log errors for debugging
- Avoid unnecessary error suppression
At LabEx, we emphasize these best practices to help developers write more robust and maintainable Go code.