Error Handling
Error Response Format
Section titled “Error Response Format”All API errors follow a consistent format:
{ "error": { "code": "SLOT_UNAVAILABLE", "message": "This time slot is no longer available", "details": {} }}Error Codes
Section titled “Error Codes”| Code | HTTP Status | Description |
|---|---|---|
UNAUTHORIZED | 401 | Missing or invalid session |
FORBIDDEN | 403 | Insufficient permissions |
NOT_FOUND | 404 | Resource not found |
VALIDATION_ERROR | 400 | Invalid request body (Zod) |
CONFLICT | 409 | Duplicate or conflicting state |
BAD_REQUEST | 400 | Generic bad request |
SLOT_UNAVAILABLE | 409 | Time slot no longer available |
INSUFFICIENT_CREDITS | 400 | Not enough enrollment credits |
POLICY_VIOLATION | 403 | Cancellation policy blocks action |
STRIPE_ERROR | 502 | Stripe API failure |
RATE_LIMITED | 429 | Too many requests |
SERVICE_UNAVAILABLE | 503 | External service down (circuit breaker open) |
Errors Helper
Section titled “Errors Helper”Services use the Errors helper for consistent error creation:
import { Errors } from '../../lib/errors';
// Throws with correct HTTP status and error codethrow Errors.notFound('Student');// → { code: 'NOT_FOUND', message: 'Student not found' }
throw Errors.badRequest('Invalid date range');throw Errors.unauthorized();throw Errors.forbidden();throw Errors.conflict('Email already registered');Validation Errors
Section titled “Validation Errors”Request body validation uses Zod. Failed validation returns:
{ "error": { "code": "VALIDATION_ERROR", "message": "Validation failed", "details": { "issues": [ { "path": ["email"], "message": "Invalid email" } ] } }}Frontend Error Handling
Section titled “Frontend Error Handling”The API client checks for error responses and surfaces them via toast notifications:
const mutation = useMutation({ mutationFn: (input) => api.post('/teacher/sessions', input), onError: (error) => { toast.error(error.message || t('common.error')); },});