{
    "name": "error-handling",
    "version": "1.0.0",
    "description": "Patterns for robust error handling across TypeScript, Python, and Go. Covers typed errors, error boundaries, retries, circuit breakers, and user-facing error messages. Use when designing error types, retries, circuit breakers, or user-facing failure messages in TypeScript, Python, or Go.",
    "system_prompt": "name error-handling description Patterns for robust error handling across TypeScript, Python, and Go. Covers typed errors, error boundaries, retries, circuit breakers, and user-facing error messages. Use when designing error types, retries, circuit breakers, or user-facing failure messages in TypeScript, Python, or Go. metadata {\"origin\":\"ECC\"} Error Handling Patterns Consistent, robust error handling patterns for production applications. When to Activate Designing error types or exception hierarchies for a new module or service Adding retry logic or circuit breakers for unreliable external dependencies Reviewing API endpoints for missing error handling Implementing user-facing error messages and feedback Debugging cascading failures or silent error swallowing Core Principles Fail fast and loudly — surface errors at the boundary where they occur; don't bury them Typed errors over string messages — errors are first-class values with structure User messages ≠ developer messages — show friendly text to users, log full context server-side Never swallow errors silently — every catch block must either handle, re-throw, or log Errors are part of your API contract — document every error code a client may receive TypeScript / JavaScript Typed Error Classes // Define an error hierarchy for your domain export class AppError extends Error { constructor ( message : string , public readonly code : string , public readonly statusCode : number = 500 , public readonly details ?: unknown , ) { super (message) this . name = this . constructor . name // Maintain correct prototype chain in transpiled ES5 JavaScript. // Required for `instanceof` checks (e.g., `error instanceof NotFoundError`) // to work correctly when extending the built-in Error class. Object . setPrototypeOf ( this , new . target . prototype ) } } export class NotFoundError extends AppError { constructor ( resource : string , id : string ) { super ( ` ${resource} not found: ${id} ` , 'NOT_FOUND' , 404 ) } } export class ValidationError extends AppError { constructor ( message : string , details : { field: string ; message: string }[] ) { super (message, 'VALIDATION_ERROR' , 422 , details) } } export class UnauthorizedError extends AppError { constructor ( reason = 'Authentication required' ) { super (reason, 'UNAUTHORIZED' , 401 ) } } export class RateLimitError extends AppError { constructor ( public readonly retryAfterMs : number ) { super ( 'Rate limit exceeded' , 'RATE_LIMITED' , 429 ) } } Result Pattern (no-throw style) For operations where failure is expected and common (parsing, external calls): type Result <T, E = AppError > = | { ok : true ; value : T } | { ok : false ; error : E } function ok<T>( value : T): Result <T> { return { ok : true , value } } function err<E>( error : E): Result < never , E> { return { ok : false , error } } // Usage async function fetchUser ( id : string ): Promise < Result < User >> { try { const user = await db. users . findUnique ({ where : { id } }) if (!user) return err ( new NotFoundError ( 'User' , id)) return ok (user) } catch (e) { return err ( new AppError ( 'Database error' , 'DB_ERROR' )) } } const result = await fetchUser ( 'abc-123' ) if (!result. ok ) { // TypeScript knows result.error here logger. error ( 'Failed to fetch user' , { error : result. error }) return } // TypeScript knows result.value here console . log (result. value . email ) API Error Handler (Next.js / Express) import { NextRequest , NextResponse } from 'next/server' function handleApiError ( error : unknown ): NextResponse { // Known application error if (error instanceof AppError ) { return NextResponse . json ( { error : { code : error. code , message : error. message , ...(error. details ? { details : error. details } : {}), }, }, { status : error. statusCode }, ) } // Zod validation error if (error instanceof z. ZodError ) { return NextResponse . json ( { error : { code : 'VALIDATION_ERROR' , message : 'Request validation failed' , details : error. issues . map ( i => ({ field : i. path . join ( '.' ), message : i. message , })), }, }, { status : 422 }, ) } // Unexpected error — log details, return generic message console . error ( 'Unexpected error:' , error) return NextResponse . json ( { error : { code : 'INTERNAL_ERROR' , message : 'An unexpected error occurred' } }, { status : 500 }, ) } export async function POST ( req : NextRequest ) { try { // ... handler logic } catch (error) { return handleApiError (error) } } React Error Boundary import { Component , ErrorInfo , ReactNode } from 'react' interface Props { fallback : ReactNode onError ?: ( error : Error , info : ErrorInfo ) => void children : ReactNode } interface State { hasError : boolean error : Error | null } export class ErrorBoundary extends Component < Props , State > { state : State = { hasError : false , error : null } static getDerivedStateFromError ( error : Error ): State { return { hasError : true , error } } componentDidCatch ( error : Error , info : ErrorInfo ) { this . props . onError ?.(error, info) console . error ( 'Unhandled React error:' , error, info) } render ( ) { if ( this . state . hasError ) return this . props . fallback return this . props . children } } // Usage < ErrorBoundary fallback={ < p > Something went wrong. Please refresh. </ p > }> < MyComponent /> </ ErrorBoundary > Python Custom Exception Hierarchy class AppError ( Exception ): \"\"\"Base application error.\"\"\" def __init__ ( self, message: str , code: str , status_code: int = 500 ): super ().__init__(message) self .code = code self .status_code = status_code class NotFoundError ( AppError ): def __init__ ( self, resource: str , id : str ): super ().__init__( f\" {resource} not found: { id } \" , \"NOT_FOUND\" , 404 ) class ValidationError ( AppError ): def __init__ ( self, message: str , details: list [ dict ] | None = None ): super ().__init__(message, \"VALIDATION_ERROR\" , 422 ) self .details = details or [] FastAPI Global Exception Handler from fastapi import FastAPI, Request from fastapi.responses import JSONResponse app = FastAPI() @app.exception_handler( AppError ) async def app_error_handler ( request: Request, exc: AppError ) -> JSONResponse: return JSONResponse( status_code=exc.status_code, content={ \"error\" : { \"code\" : exc.code, \"message\" : str (exc)}}, ) @app.exception_handler( Exception ) async def generic_error_handler ( request: Request, exc: Exception ) -> JSONResponse: # Log full details, return generic message logger.exception( \"Unexpected error\" , exc_info=exc) return JSONResponse( status_code= 500 , content={ \"error\" : { \"code\" : \"INTERNAL_ERROR\" , \"message\" : \"An unexpected error occurred\" }}, ) Go Sentinel Errors and Error Wrapping package domain import \"errors\" // Sentinel errors for type-checking var ( ErrNotFound = errors.New( \"not found\" ) ErrUnauthorized = errors.New( \"unauthorized\" ) ErrConflict = errors.New( \"conflict\" ) ) // Wrap errors with context — never lose the original func (r *UserRepository) FindByID(ctx context.Context, id string ) (*User, error ) { user, err := r.db.QueryRow(ctx, \"SELECT * FROM users WHERE id = $1\" , id) if errors.Is(err, sql.ErrNoRows) { return nil , fmt.Errorf( \"user %s: %w\" , id, ErrNotFound) } if err != nil { return nil , fmt.Errorf( \"querying user %s: %w\" , id, err) } return user, nil } // At the handler level, unwrap to determine response func (h *Handler) GetUser(w http.ResponseWriter, r *http.Request) { user, err := h.service.GetUser(r.Context(), chi.URLParam(r, \"id\" )) if err != nil { switch { case errors.Is(err, domain.ErrNotFound): writeError(w, http.StatusNotFound, \"not_found\" , err.Error()) case errors.Is(err, domain.ErrUnauthorized): writeError(w, http.StatusForbidden, \"forbidden\" , \"Access denied\" ) default : slog.Error( \"unexpected error\" , \"err\" , err) writeError(w, http.StatusInternalServerError, \"internal_error\" , \"An unexpected error occurred\" ) } return } writeJSON(w, http.StatusOK, user) } Retry with Exponential Backoff interface RetryOptions { maxAttempts ?: number baseDelayMs ?: number maxDelayMs ?: number retryIf ?: ( error : unknown ) => boolean } async function withRetry<T>( fn : () => Promise <T>, options : RetryOptions = {}, ): Promise <T> { const { maxAttempts = 3 , baseDelayMs = 500 , maxDelayMs = 10_000 , retryIf = () => true , } = options let lastError : unknown for ( let attempt = 1 ; attempt <= maxAttempts; attempt++) { try { return await fn () } catch (error) { lastError = error if (attempt === maxAttempts || ! retryIf (error)) throw error const jitter = Math . random () * baseDelayMs const delay = Math . min (baseDelayMs * 2 ** (attempt - 1 ) + jitter, maxDelayMs) await new Promise ( resolve => setTimeout (resolve, delay)) } } throw lastError } // Usage: retry transient network errors, not 4xx const data = await withRetry ( () => fetch ( '/api/data' ). then ( r => r. json ()), { maxAttempts : 3 , retryIf : ( error ) => !(error instanceof AppError && error. statusCode < 500 ), }) User-Facing Error Messages Map error codes to human-readable messages. Keep technical details out of user-visible text. const USER_ERROR_MESSAGES : Record < string , string > = { NOT_FOUND : 'The requested item could not be found.' , UNAUTHORIZED : 'Please sign in to continue.' , FORBIDDEN : \"You don't have permission to do that.\" , VALIDATION_ERROR : 'Please check your input and try again.' , RATE_LIMITED : 'Too many requests. Please wait a moment and try again.' , INTERNAL_ERROR : 'Something went wrong on our end. Please try again later.' , } export function getUserMessage ( code : string ): string { return USER_ERROR_MESSAGES [code] ?? USER_ERROR_MESSAGES . INTERNAL_ERROR } Error Handling Checklist Before merging any code that touches error handling: Every catch block handles, re-throws, or logs — no silent swallowing API errors follow the standard envelope { error: { code, message } } User-facing messages contain no stack traces or internal details Full error context is logged server-side Custom error classes extend a base AppError with a code field Async functions surface errors to callers — no fire-and-forget without fallback Retry logic only retries retriable errors (not 4xx client errors) React components are wrapped in ErrorBoundary for rendering errors",
    "model_config": {
        "provider": "deepseek",
        "model": "deepseek-chat",
        "temperature": 0.7,
        "max_tokens": 4096,
        "top_p": 0.9
    },
    "trigger_words": [],
    "source": "DeepseekModel",
    "source_url": "https://deepseekmodel.com/skill?id=affaan-m-ecc-skills-error-handling-skill-md"
}