Claude Code Plugins

Community-maintained marketplace

Feedback

Go error handling patterns including wrapping, custom error types, errors.Is/As, and error conventions. Use when handling, creating, or checking errors in Go.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name go-error-handling
description Go error handling patterns including wrapping, custom error types, errors.Is/As, and error conventions. Use when handling, creating, or checking errors in Go.

Go Error Handling

Expert guidance for proper error handling in Go.

Quick Reference

Operation Pattern Example
Wrap with context fmt.Errorf with %w fmt.Errorf("opening file: %w", err)
Create custom error struct with Error() type ValidationError struct {...}
Check error type errors.Is errors.Is(err, ErrNotFound)
Extract error errors.As errors.As(err, &validationErr)
Sentinel errors var at package level var ErrNotFound = errors.New("not found")
Ignore errors Never Always check err != nil

What Do You Need?

  1. Error wrapping - Adding context to errors
  2. Custom error types - Creating structured errors
  3. Error inspection - errors.Is, errors.As
  4. Sentinel errors - Package-level error values
  5. Error conventions - When to wrap, return, or create

Specify a number or describe your error handling scenario.

Routing

Response Reference to Read
1, "wrap", "context", "fmt.Errorf" wrapping.md
2, "custom", "type", "struct" custom-errors.md
3, "check", "errors.Is", "errors.As" inspection.md
4, "sentinel", "package", "global" sentinel.md
5, general error handling Read relevant references

Critical Rules

  • Never ignore errors: Always check err != nil
  • Wrap with %w: Use %w to preserve error type for errors.Is
  • Wrap at boundaries: Wrap when crossing package boundaries
  • Don't wrap twice: Avoid double-wrapping the same error
  • Use errors.Is for sentinel: Check if error is a specific value
  • Use errors.As for types: Extract and inspect custom error types

Error Handling Patterns

Wrapping Errors

// Good: Wrap with context using %w
func (s *Service) Process(id string) error {
    item, err := s.repo.Find(id)
    if err != nil {
        return fmt.Errorf("finding item %s: %w", id, err)
    }
    // ...
}

// Bad: Wrapping with %v loses error type
return fmt.Errorf("finding item %s: %v", id, err)  // Can't use errors.Is()

// Bad: Double wrapping
return fmt.Errorf("processing: %w", fmt.Errorf("finding: %w", err))

Custom Error Types

// Define custom error type
type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation failed for field %s: %s", e.Field, e.Message)
}

// Return custom error
func (s *Service) Validate(input Input) error {
    if input.Email == "" {
        return &ValidationError{
            Field:   "email",
            Message: "is required",
        }
    }
    return nil
}

Error Inspection

// Check for sentinel error
if errors.Is(err, ErrNotFound) {
    // Handle not found
}

// Extract and check custom error type
var validationErr *ValidationError
if errors.As(err, &validationErr) {
    // Access validationErr.Field, validationErr.Message
}

// Check multiple possibilities
if errors.Is(err, ErrNotFound) || errors.Is(err, ErrAccessDenied) {
    // Handle both cases
}

Sentinel Errors

// Package-level sentinel errors
var (
    ErrNotFound    = errors.New("not found")
    ErrAccessDenied = errors.New("access denied")
    ErrInvalidInput = errors.New("invalid input")
)

// Use in returns
func (r *Repository) Find(id string) (*Item, error) {
    // ...
    return nil, ErrNotFound
}

// Check in callers
if err != nil {
    if errors.Is(err, ErrNotFound) {
        return nil, nil  // Not found is not an error here
    }
    return nil, err  // Other errors are still errors
}

When to Wrap vs Return

Scenario Action
Crossing package boundary Wrap with context
Internal function Return as-is
Adding retry logic Don't wrap (check with errors.Is)
Adding logging Log then wrap or return
API layer Wrap for user-friendly messages

Common Mistakes

Mistake Severity Fix
Ignoring errors Critical Always check err != nil
Using %v instead of %w High Use %w to preserve error type
Double wrapping Medium Wrap only at boundary
Panicking on errors Critical Return errors, don't panic
Creating strings for errors Low Use errors.New() or sentinel
Wrapping nil error Medium Check err != nil before wrapping

Reference Index

File Topics
wrapping.md fmt.Errorf with %w, when to wrap
custom-errors.md Error types, methods, best practices
inspection.md errors.Is, errors.As, type switches
sentinel.md Package-level errors, comparison

Success Criteria

Error handling is correct when:

  • No errors are ignored (all checked)
  • Errors wrapped at package boundaries with %w
  • Custom error types for domain-specific errors
  • Sentinel errors for expected conditions
  • errors.Is used for sentinel checking
  • errors.As used for type inspection
  • No panic on errors (except in package init/main)