Skip to content
NeuralSkills
Code Review

Error Handling Review

Review error handling patterns: try/catch usage, error boundaries, user feedback, and graceful degradation.

Intermediate Free Published: April 15, 2026
Compatible Tools claude-codechatgptgeminicopilotcursorwindsurfuniversal

The Problem

Error handling is the most neglected dimension of code quality. Developers wrap everything in try/catch and log to console — silently swallowing failures that should crash loudly. Network requests assume success. Form submissions show nothing when the API returns 500. Database operations lack retry logic. The result: users see blank screens, data corrupts silently, and debugging becomes forensic archaeology because errors were caught and discarded.

The Prompt

Review the error handling in the following code. Act as a reliability engineer evaluating how the system behaves when things go wrong.

LANGUAGE/FRAMEWORK: [e.g., TypeScript/React, Python/FastAPI, Go]
CONTEXT: [e.g., payment processing, user registration, file upload]

CODE:
[paste your code here]

Evaluate these error handling dimensions:

1. **Catch Quality**
   - Are catch blocks too broad (catching Error instead of specific types)?
   - Do catch blocks swallow errors silently (empty catch, console.log only)?
   - Are errors re-thrown when they should bubble up?
   - Is the original error preserved in wrapped exceptions (cause chaining)?

2. **User Communication**
   - Does the user see a helpful message when something fails?
   - Are error states designed, or does the UI just go blank?
   - Are transient errors (network, timeout) distinguished from permanent ones?
   - Is there a retry mechanism for recoverable failures?

3. **Boundary Protection**
   - Are API responses validated before use?
   - Do database operations have transaction rollback on failure?
   - Are file operations wrapped with proper cleanup (finally blocks)?
   - Do external service calls have timeouts configured?

4. **Error Propagation**
   - Is the error propagation strategy consistent (throw vs return Result vs callback)?
   - Can the caller distinguish between error types to decide recovery strategy?
   - Are async errors handled (unhandled promise rejections)?

5. **Observability**
   - Are errors logged with sufficient context (user ID, request ID, input data)?
   - Are error rates monitored (not just logged)?
   - Do structured logs enable filtering and alerting?

6. **Edge Cases**
   - What happens with empty inputs, null values, or malformed data?
   - Are race conditions handled (double submit, stale data)?
   - Is there a global error boundary / unhandled rejection handler?

For each issue, provide:
- **Location**: File and line
- **Failure Mode**: What happens when this fails in production
- **Severity**: silent-failure / poor-ux / data-risk / crash
- **Fix**: Improved error handling code

Example Output

## Error Handling Review: 5 issues found

### Silent Failure: Swallowed Database Error
Location: src/services/user.ts:34
Code:
  try { await db.insert(user); }
  catch (e) { console.log('insert failed'); }
Failure Mode: User sees success message but data was never saved.
Fix:
  try { await db.insert(user); }
  catch (error) {
    logger.error('User insert failed', { userId: user.id, error });
    throw new DatabaseError('Failed to create user', { cause: error });
  }

### Poor UX: Unhandled Loading State
Location: src/components/Dashboard.tsx:18
Code: `const { data } = useSWR('/api/stats')` — no error or loading handling.
Failure Mode: Component renders with undefined data, shows blank or crashes.
Fix:
  const { data, error, isLoading } = useSWR('/api/stats');
  if (isLoading) return <Skeleton />;
  if (error) return <ErrorCard message="Failed to load dashboard" retry={mutate} />;

When to Use

Run this on code that handles user input, network requests, database operations, or payment processing — anywhere failure has consequences. Essential before production deployments and after any incident where “the error was caught but nobody noticed” was the root cause.

Pro Tips

  • Test the unhappy path — after the review, ask “Generate test cases that exercise every error path in this code” to verify your error handling actually works.
  • Ask for error taxonomy — request “Categorize all possible errors into recoverable (retry), user-fixable (show form errors), and fatal (show error page)” for a structured approach.
  • Check error boundaries — in React apps, ask “Where should React Error Boundaries be placed to prevent the entire app from crashing?”