error-handling

Error handling patterns across languages and layers — operational vs programmer errors, retry strategies, circuit breakers, error boundaries, HTTP responses, graceful degradation, and structured logging. Use when designing error strategies, building resilient APIs, or reviewing error management.

7 stars

Best use case

error-handling is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Error handling patterns across languages and layers — operational vs programmer errors, retry strategies, circuit breakers, error boundaries, HTTP responses, graceful degradation, and structured logging. Use when designing error strategies, building resilient APIs, or reviewing error management.

Teams using error-handling should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/error-handling/SKILL.md --create-dirs "https://raw.githubusercontent.com/wpank/ai/main/skills/api/error-handling/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/error-handling/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How error-handling Compares

Feature / Agenterror-handlingStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Error handling patterns across languages and layers — operational vs programmer errors, retry strategies, circuit breakers, error boundaries, HTTP responses, graceful degradation, and structured logging. Use when designing error strategies, building resilient APIs, or reviewing error management.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Error Handling Patterns

> Ship resilient software. Handle errors at boundaries, fail fast and loud, never swallow exceptions silently.

## Error Handling Philosophy

| Principle | Description |
|-----------|-------------|
| **Fail Fast** | Detect errors early — validate inputs at the boundary, not deep in business logic |
| **Fail Loud** | Errors must be visible — log them, surface them, alert on them |
| **Handle at Boundaries** | Catch and translate errors at layer boundaries (controller, middleware, gateway) |
| **Let It Crash** | For unrecoverable state, crash and restart (Erlang/OTP philosophy) |
| **Be Specific** | Catch specific error types, never bare `catch` or `except` |
| **Provide Context** | Every error carries enough context to diagnose without reproducing |


## Installation

### OpenClaw / Moltbot / Clawbot

```bash
npx clawhub@latest install error-handling
```


---

## Error Types

**Operational errors** — network timeouts, invalid user input, file not found, DB connection lost. Handle gracefully.

**Programmer errors** — `TypeError`, null dereference, assertion failures. Fix the code — don't catch and suppress.

```javascript
// Operational — handle gracefully
try {
  const data = await fetch('/api/users');
} catch (err) {
  if (err.code === 'ECONNREFUSED') return fallbackData;
  throw err; // re-throw unexpected errors
}

// Programmer — let it crash, fix the bug
const user = null;
user.name; // TypeError — don't try/catch this
```

---

## Language Patterns

| Language | Mechanism | Anti-Pattern |
|----------|-----------|-------------|
| **JavaScript** | `try/catch`, `Promise.catch`, Error subclasses | `.catch(() => {})` swallowing errors |
| **Python** | Exceptions, context managers (`with`) | Bare `except:` catching everything |
| **Go** | `error` returns, `errors.Is/As`, `fmt.Errorf` wrapping | `_ = riskyFunction()` ignoring error |
| **Rust** | `Result<T, E>`, `Option<T>`, `?` operator | `.unwrap()` in production code |

### JavaScript — Error Subclasses

```javascript
class AppError extends Error {
  constructor(message, code, statusCode, details = {}) {
    super(message);
    this.name = this.constructor.name;
    this.code = code;
    this.statusCode = statusCode;
    this.details = details;
    this.isOperational = true;
  }
}

class NotFoundError extends AppError {
  constructor(resource, id) {
    super(`${resource} not found`, 'NOT_FOUND', 404, { resource, id });
  }
}

class ValidationError extends AppError {
  constructor(errors) {
    super('Validation failed', 'VALIDATION_ERROR', 422, { errors });
  }
}
```

### Go — Error Wrapping

```go
func GetUser(id string) (*User, error) {
    row := db.QueryRow("SELECT * FROM users WHERE id = $1", id)
    var user User
    if err := row.Scan(&user.ID, &user.Name); err != nil {
        if errors.Is(err, sql.ErrNoRows) {
            return nil, fmt.Errorf("user %s: %w", id, ErrNotFound)
        }
        return nil, fmt.Errorf("querying user %s: %w", id, err)
    }
    return &user, nil
}
```

---

## Error Boundaries

### Express Error Middleware

```javascript
app.use((err, req, res, next) => {
  const statusCode = err.statusCode || 500;
  const response = {
    error: {
      code: err.code || 'INTERNAL_ERROR',
      message: err.isOperational ? err.message : 'Something went wrong',
      ...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
      requestId: req.id,
    },
  };

  logger.error('Request failed', {
    err, requestId: req.id, method: req.method, path: req.path,
  });

  res.status(statusCode).json(response);
});
```

### React Error Boundary

```tsx
import { ErrorBoundary } from 'react-error-boundary';

function ErrorFallback({ error, resetErrorBoundary }) {
  return (
    <div role="alert">
      <h2>Something went wrong</h2>
      <pre>{error.message}</pre>
      <button onClick={resetErrorBoundary}>Try again</button>
    </div>
  );
}

<ErrorBoundary FallbackComponent={ErrorFallback} onReset={() => queryClient.clear()}>
  <App />
</ErrorBoundary>
```

---

## Retry Patterns

| Pattern | When to Use | Config |
|---------|-------------|--------|
| **Exponential Backoff** | Transient failures (network, 503) | Base 1s, max 30s, factor 2x |
| **Backoff + Jitter** | Multiple clients retrying | Random ±30% on each delay |
| **Circuit Breaker** | Downstream service failing repeatedly | Open after 5 failures, half-open after 30s |
| **Bulkhead** | Isolate failures to prevent cascade | Limit concurrent calls per service |
| **Timeout** | Prevent indefinite hangs | Connect 5s, read 30s, total 60s |

### Exponential Backoff with Jitter

```javascript
async function withRetry(fn, { maxRetries = 3, baseDelay = 1000, maxDelay = 30000 } = {}) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (attempt === maxRetries || !isRetryable(err)) throw err;
      const delay = Math.min(baseDelay * 2 ** attempt, maxDelay);
      const jitter = delay * (0.7 + Math.random() * 0.6);
      await new Promise((r) => setTimeout(r, jitter));
    }
  }
}

function isRetryable(err) {
  return [408, 429, 500, 502, 503, 504].includes(err.statusCode) || err.code === 'ECONNRESET';
}
```

### Circuit Breaker

```javascript
class CircuitBreaker {
  constructor({ threshold = 5, resetTimeout = 30000 } = {}) {
    this.state = 'CLOSED';       // CLOSED → OPEN → HALF_OPEN → CLOSED
    this.failureCount = 0;
    this.threshold = threshold;
    this.resetTimeout = resetTimeout;
    this.nextAttempt = 0;
  }

  async call(fn) {
    if (this.state === 'OPEN') {
      if (Date.now() < this.nextAttempt) throw new Error('Circuit is OPEN');
      this.state = 'HALF_OPEN';
    }
    try {
      const result = await fn();
      this.onSuccess();
      return result;
    } catch (err) {
      this.onFailure();
      throw err;
    }
  }

  onSuccess() { this.failureCount = 0; this.state = 'CLOSED'; }
  onFailure() {
    this.failureCount++;
    if (this.failureCount >= this.threshold) {
      this.state = 'OPEN';
      this.nextAttempt = Date.now() + this.resetTimeout;
    }
  }
}
```

---

## HTTP Error Responses

| Status | Name | When to Use |
|--------|------|-------------|
| **400** | Bad Request | Malformed syntax, invalid JSON |
| **401** | Unauthorized | Missing or invalid authentication |
| **403** | Forbidden | Authenticated but insufficient permissions |
| **404** | Not Found | Resource does not exist |
| **409** | Conflict | Request conflicts with current state |
| **422** | Unprocessable Entity | Valid syntax but semantic errors |
| **429** | Too Many Requests | Rate limit exceeded (include `Retry-After`) |
| **500** | Internal Server Error | Unexpected server failure |
| **502** | Bad Gateway | Upstream returned invalid response |
| **503** | Service Unavailable | Temporarily overloaded or maintenance |

### Standard Error Envelope

```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The request body contains invalid fields.",
    "details": [
      { "field": "email", "message": "Must be a valid email address" }
    ],
    "requestId": "req_abc123xyz"
  }
}
```

---

## Graceful Degradation

| Strategy | Example |
|----------|---------|
| **Fallback values** | Show cached avatar when image service is down |
| **Feature flags** | Disable unstable recommendation engine |
| **Cached responses** | Serve stale data with `X-Cache: STALE` header |
| **Partial response** | Return available data with `warnings` array |

```javascript
async function getProductPage(productId) {
  const product = await productService.get(productId); // critical — propagate errors

  const [reviews, recommendations] = await Promise.allSettled([
    reviewService.getForProduct(productId),
    recommendationService.getForProduct(productId),
  ]);

  return {
    product,
    reviews: reviews.status === 'fulfilled' ? reviews.value : [],
    recommendations: recommendations.status === 'fulfilled' ? recommendations.value : [],
    warnings: [reviews, recommendations]
      .filter((r) => r.status === 'rejected')
      .map((r) => ({ service: 'degraded', reason: r.reason.message })),
  };
}
```

---

## Logging & Monitoring

| Practice | Implementation |
|----------|---------------|
| **Structured logging** | JSON: `level`, `message`, `error`, `requestId`, `userId`, `timestamp` |
| **Error tracking** | Sentry, Datadog, Bugsnag — automatic capture with source maps |
| **Alert thresholds** | Error rate > 1%, P99 latency > 2s, 5xx spike |
| **Correlation IDs** | Pass `requestId` through all service calls |
| **Log levels** | `error` = needs attention, `warn` = degraded, `info` = normal, `debug` = dev |

---

## Anti-Patterns

| Anti-Pattern | Fix |
|-------------|-----|
| **Swallowing errors** `catch (e) {}` | Log and re-throw, or handle explicitly |
| **Generic catch-all** at every level | Catch specific types, let unexpected errors bubble |
| **Error as control flow** | Use conditionals, return values, or option types |
| **Stringly-typed errors** `throw "wrong"` | Throw `Error` objects with codes and context |
| **Logging and throwing** | Log at the boundary only, or wrap and re-throw |
| **Catch-and-return-null** | Return `Result` type, throw, or return error object |
| **Ignoring Promise rejections** | Always `await` or attach `.catch()` |
| **Exposing internals** | Sanitize responses; log details server-side only |

---

## NEVER Do

1. **NEVER swallow errors silently** — `catch (e) {}` hides bugs and causes silent data corruption
2. **NEVER expose stack traces, SQL errors, or file paths in API responses** — log details server-side only
3. **NEVER use string throws** — `throw 'error'` has no stack trace, no type, no context
4. **NEVER catch and return null without explanation** — callers have no idea why the operation failed
5. **NEVER ignore unhandled Promise rejections** — always `await` or attach `.catch()`
6. **NEVER cache error responses** — 5xx and transient errors must not be cached and re-served
7. **NEVER use exceptions for normal control flow** — exceptions are for exceptional conditions
8. **NEVER return generic "Something went wrong" without logging the real error** — always log the full error server-side with request context

Related Skills

schema-markup

7
from wpank/ai

Add, fix, or optimize schema markup and structured data. Use when the user mentions schema markup, structured data, JSON-LD, rich snippets, schema.org, FAQ schema, product schema, review schema, or breadcrumb schema.

prompt-engineering

7
from wpank/ai

Master advanced prompt engineering techniques to maximize LLM performance, reliability, and controllability in production. Use when optimizing prompts, improving LLM outputs, designing production prompt templates, or building AI-powered features.

professional-communication

7
from wpank/ai

Write effective professional messages for software teams. Use when drafting emails, Slack/Teams messages, meeting agendas, status updates, or translating technical concepts for non-technical audiences. Triggers on email, slack, teams, message, meeting agenda, status update, stakeholder communication, escalation, jargon translation.

persona-docs

7
from wpank/ai

Create persona documentation for a product or codebase. Use when asked to create persona docs, document target users, define user journeys, document onboarding flows, or when starting a new product and needing to define its audience. Persona docs should be the first documentation created for any product.

mermaid-diagrams

7
from wpank/ai

Create software diagrams using Mermaid syntax. Use when users need to create, visualize, or document software through diagrams including class diagrams, sequence diagrams, flowcharts, ERDs, C4 architecture diagrams, state diagrams, git graphs, and other diagram types. Triggers include requests to diagram, visualize, model, map out, or show the flow of a system.

game-changing-features

7
from wpank/ai

Find 10x product opportunities and high-leverage improvements. Use when the user wants strategic product thinking, mentions 10x, wants to find high-impact features, or asks what would make a product dramatically more valuable.

clear-writing

7
from wpank/ai

Write clear, concise prose for humans — documentation, READMEs, API docs, commit messages, error messages, UI text, reports, and explanations. Combines Strunk's rules for clearer prose with technical documentation patterns, structure templates, and review checklists.

brainstorming

7
from wpank/ai

Explore ideas before implementation through collaborative dialogue. Use before any creative work — creating features, building components, adding functionality, or modifying behavior. Turns ideas into fully formed designs and specs through structured conversation.

Article Illustrator

7
from wpank/ai

When the user wants to add illustrations to an article or blog post. Triggers on: "illustrate article", "add images to article", "generate illustrations", "article images", or requests to visually enhance written content. Analyzes article structure, identifies positions for visual aids, and generates illustrations using a Type x Style two-dimension approach.

subagent-driven-development

7
from wpank/ai

Execute implementation plans by dispatching a fresh subagent per task with two-stage review (spec compliance then code quality). Use when you have an implementation plan with mostly independent tasks and want high-quality, fast iteration within a single session.

skill-judge

7
from wpank/ai

Evaluate Agent Skill quality against official specifications. Use when reviewing SKILL.md files, auditing skill packages, improving skill design, or checking if a skill follows best practices. Provides 8-dimension scoring (120 points) with actionable improvements. Triggers on review skill, evaluate skill, audit skill, improve skill, skill quality, SKILL.md review.

skill-creator

7
from wpank/ai

WHAT: Guide for creating effective AI agent skills - modular packages that extend Claude's capabilities with specialized knowledge, workflows, and tools. WHEN: User wants to create, write, author, or update a skill. User asks about skill structure, SKILL.md format, or how to package domain knowledge for AI agents. KEYWORDS: "create a skill", "make a skill", "new skill", "skill template", "SKILL.md", "agent skill", "write a skill", "skill structure", "package a skill"