---
title: Use Custom Error Types
impact: HIGH
impactDescription: enables proper error categorization and handling
tags: error-handling, custom-errors, patterns, quality
---

## Use Custom Error Types

Custom error types enable proper error handling, categorization, and monitoring. They provide clear contracts for API consumers.

**Incorrect (generic errors):**

```go
return errors.New("user not found")
return errors.New("invalid input")
return errors.New("database connection failed")
```

**Correct (custom error structs):**

```go
// Base application error type can be useful but Go often uses simple structs
type AppError struct {
    Code       string
    Message    string
    StatusCode int
    Context    map[string]any
}

func (e *AppError) Error() string {
    return e.Message
}

// Specific errors
type UserNotFoundError struct {
    UserID string
}

func (e UserNotFoundError) Error() string {
    return fmt.Sprintf("user %s not found", e.UserID)
}

type ValidationError struct {
    Field   string
    Message string
}

func (e ValidationError) Error() string {
    return fmt.Sprintf("validation error on %s: %s", e.Field, e.Message)
}

// Usage
return UserNotFoundError{UserID: "123"}
return ValidationError{Field: "email", Message: "invalid format"}

// Handling
if errors.As(err, &UserNotFoundError{}) {
    // handle 404
}
```

**Benefits:**
- Type-safe error handling using `errors.As`
- Automatic HTTP status mapping
- Structured error context
- Consistent error format

**Tools:** GolangCI-Lint, Code Convention
