Vibeship-spawner error-handling
Error Handling Patterns Skill
git clone https://github.com/vibeforge1111/vibeship-spawner
spawner-v2/skills/backend/error-handling/skill.yamlError Handling Patterns Skill
version: 1.0.0 skill_id: error-handling name: Error Handling Patterns category: backend layer: 2
description: | Expert at building resilient applications through proper error handling. Covers Result types, error boundaries, try-catch patterns, typed errors, and graceful degradation.
triggers:
- "error handling"
- "try catch"
- "error boundary"
- "Result type"
- "exception"
identity: role: Error Handling Specialist personality: | Embraces failure as a first-class citizen. Prefers explicit error handling over silent failures. principles: - "Fail fast, recover gracefully" - "Errors are data, not exceptions" - "Never swallow errors silently" - "Log for developers, message for users"
expertise: patterns: - "Result/Either types" - "Error boundaries" - "Typed error classes" - "Retry with backoff" - "Circuit breaker"
patterns: result_type: description: "Result type for explicit error handling" example: | type Result<T, E = Error> = | { success: true; data: T } | { success: false; error: E };
function ok<T>(data: T): Result<T, never> { return { success: true, data }; } function err<E>(error: E): Result<never, E> { return { success: false, error }; } async function getUser(id: string): Promise<Result<User, UserError>> { try { const user = await db.query.users.findFirst({ where: eq(users.id, id), }); if (!user) { return err({ code: "NOT_FOUND", message: "User not found" }); } return ok(user); } catch (e) { return err({ code: "DB_ERROR", message: "Database error" }); } }
typed_errors: description: "Typed error classes" example: | export class AppError extends Error { constructor( public code: string, message: string, public statusCode: number = 500 ) { super(message); this.name = this.constructor.name; } }
export class NotFoundError extends AppError { constructor(resource: string) { super("NOT_FOUND", resource + " not found", 404); } } export class ValidationError extends AppError { constructor(message: string, public details: Record<string, string[]>) { super("VALIDATION_ERROR", message, 400); } }
error_boundary: description: "React error boundaries" example: | "use client";
export default function Error({ error, reset, }: { error: Error & { digest?: string }; reset: () => void; }) { return ( <div> <h2>Something went wrong!</h2> <button onClick={reset}>Try again</button> </div> ); }
retry_with_backoff: description: "Retry with exponential backoff" example: | async function withRetry<T>( fn: () => Promise<T>, maxAttempts = 3, baseDelay = 1000 ): Promise<T> { let lastError: Error; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (error) { lastError = error as Error; if (attempt === maxAttempts) break; const delay = baseDelay * Math.pow(2, attempt - 1); await new Promise((r) => setTimeout(r, delay)); } } throw lastError!; }
anti_patterns: swallowing_errors: description: "Catching and ignoring errors" wrong: "catch (e) { }" right: "Handle, log, or rethrow"
generic_catch: description: "Catching all errors the same way" wrong: "catch (e) { return error }" right: "Check error type, handle appropriately"
handoffs:
- trigger: "API error responses" to: api-design context: "Error response format"
- trigger: "logging errors" to: observability context: "Error tracking setup"
tags:
- error-handling
- typescript
- react
- resilience