Marketplace
error-handling
Modern Go error handling patterns (Go 1.13+). Use when handling, creating, or wrapping errors.
$ 설치
git clone https://github.com/IvanTorresEdge/molcajete.ai /tmp/molcajete.ai && cp -r /tmp/molcajete.ai/tech-stacks/go/skills/error-handling ~/.claude/skills/molcajete-ai// tip: Run this command in your terminal to install the skill
SKILL.md
name: error-handling description: Modern Go error handling patterns (Go 1.13+). Use when handling, creating, or wrapping errors.
Error Handling Skill
Modern error handling patterns following Go 1.13+ conventions.
When to Use
Use this skill when:
- Creating errors
- Wrapping errors
- Checking error types
- Implementing error handling logic
Error Creation
Sentinel Errors
var (
ErrNotFound = errors.New("not found")
ErrUnauthorized = errors.New("unauthorized")
ErrInvalidInput = errors.New("invalid input")
)
// Usage
if user == nil {
return ErrNotFound
}
Error Wrapping
// Wrap errors with context
func GetUser(ctx context.Context, id int) (*User, error) {
user, err := db.Query(ctx, id)
if err != nil {
return nil, fmt.Errorf("failed to get user %d: %w", id, err)
}
return user, nil
}
Custom Error Types
type ValidationError struct {
Field string
Value interface{}
Err error
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation failed for %s=%v: %v", e.Field, e.Value, e.Err)
}
func (e *ValidationError) Unwrap() error {
return e.Err
}
Error Checking
errors.Is
// Check for specific error
if errors.Is(err, ErrNotFound) {
return http.StatusNotFound
}
// Works with wrapped errors
err := fmt.Errorf("database error: %w", ErrNotFound)
errors.Is(err, ErrNotFound) // true
errors.As
// Type assertion for error details
var validationErr *ValidationError
if errors.As(err, &validationErr) {
log.Printf("validation failed: field=%s", validationErr.Field)
}
Error Handling Patterns
Check-Early-Return
func ProcessUser(ctx context.Context, id int) error {
user, err := GetUser(ctx, id)
if err != nil {
return fmt.Errorf("get user: %w", err)
}
if err := ValidateUser(user); err != nil {
return fmt.Errorf("validate user: %w", err)
}
if err := SaveUser(ctx, user); err != nil {
return fmt.Errorf("save user: %w", err)
}
return nil
}
Error Context
// Add context to errors
func (s *Service) CreateOrder(ctx context.Context, order *Order) error {
if err := s.validateOrder(order); err != nil {
return fmt.Errorf("validation failed: %w", err)
}
if err := s.repo.Save(ctx, order); err != nil {
return fmt.Errorf("failed to save order %d: %w", order.ID, err)
}
return nil
}
Error Propagation
Simple Propagation
func GetUser(id int) (*User, error) {
user, err := db.QueryUser(id)
if err != nil {
return nil, fmt.Errorf("query user: %w", err)
}
return user, nil
}
Multi-Error Handling
func ProcessBatch(items []Item) error {
var errs []error
for _, item := range items {
if err := ProcessItem(item); err != nil {
errs = append(errs, fmt.Errorf("item %d: %w", item.ID, err))
}
}
if len(errs) > 0 {
return fmt.Errorf("batch processing failed: %v", errs)
}
return nil
}
Panic vs Error
Use Errors (Preferred)
// Good - return error
func Divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
Use Panic (Rare)
// Only for truly exceptional, unrecoverable situations
func MustCompile(pattern string) *regexp.Regexp {
re, err := regexp.Compile(pattern)
if err != nil {
panic(fmt.Sprintf("invalid pattern: %v", err))
}
return re
}
Recover from Panic
func SafeHandler(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("panic: %v", err)
http.Error(w, "Internal Server Error", 500)
}
}()
// handler logic
}
Error Handling in Goroutines
Use Channels
func ProcessAsync(ctx context.Context) error {
errCh := make(chan error, 1)
go func() {
errCh <- doWork(ctx)
}()
select {
case <-ctx.Done():
return ctx.Err()
case err := <-errCh:
return err
}
}
Use errgroup
import "golang.org/x/sync/errgroup"
func ProcessParallel(ctx context.Context, items []Item) error {
g, ctx := errgroup.WithContext(ctx)
for _, item := range items {
item := item // capture range variable
g.Go(func() error {
return processItem(ctx, item)
})
}
return g.Wait()
}
Best Practices
- Always check errors - Never ignore with
_ - Wrap errors with context - Use
fmt.Errorf("context: %w", err) - Use errors.Is - For checking specific errors
- Use errors.As - For type assertions
- Return early - Check errors immediately
- Don't panic - Use errors for expected failures
- Add context - Make errors debuggable
- Wrap, don't replace - Preserve error chain
Anti-Patterns
Don't Ignore Errors
// Bad
data, _ := ioutil.ReadFile("config.json")
// Good
data, err := ioutil.ReadFile("config.json")
if err != nil {
return fmt.Errorf("failed to read config: %w", err)
}
Don't Lose Error Context
// Bad - loses original error
if err != nil {
return errors.New("failed to process")
}
// Good - preserves error chain
if err != nil {
return fmt.Errorf("failed to process: %w", err)
}
Don't Panic for Expected Errors
// Bad
func GetConfig() *Config {
data, err := ioutil.ReadFile("config.json")
if err != nil {
panic(err) // Don't do this
}
// ...
}
// Good
func GetConfig() (*Config, error) {
data, err := ioutil.ReadFile("config.json")
if err != nil {
return nil, fmt.Errorf("read config: %w", err)
}
// ...
}
Repository

IvanTorresEdge
Author
IvanTorresEdge/molcajete.ai/tech-stacks/go/skills/error-handling
0
Stars
0
Forks
Updated15h ago
Added1w ago