Vibeship-spawner error-handling

Error Handling Patterns Skill

install
source · Clone the upstream repo
git clone https://github.com/vibeforge1111/vibeship-spawner
manifest: spawner-v2/skills/backend/error-handling/skill.yaml
source content

Error 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