Errors happen everywhere
In a full-stack app, errors can occur at every layer:Layer 1: Backend errors (FastAPI)
FastAPI provides structured error responses. UseHTTPException for expected errors:
{ "name": 123 } instead of a string, FastAPI returns a 422 with details — you don’t need to code this.
Common HTTP status codes for errors
Layer 2: API client (JavaScript)
Your API client translates HTTP errors into JavaScript errors:- Network errors —
fetch()itself throws (no response at all) - Validation errors — 422 with field-level details from Pydantic
- Other HTTP errors — 404, 409, 500, etc. with
detailmessage from FastAPI
Layer 3: React components
Components catch errors and display them to the user:- Global errors (top of form) — network errors, server errors, unexpected issues
- Field errors (next to inputs) — validation errors for specific fields
Page-level error handling
For data fetching errors, use the early return pattern:The “Try Again” button calls
loadUsers() directly. It resets the error, shows loading, and retries the fetch. Simple and effective.The error flow — from backend to user
detail message you write in Python shows up directly on the user’s screen. Write it for humans, not for developers.
Error handling checklist
Every component that makes API calls should handle:- Network failures — “Unable to connect” message with retry option
- Validation errors — field-level messages next to inputs
- Not found (404) — “Record not found” message
- Conflict (409) — “Already exists” message
- Server errors (500) — “Something went wrong” with retry option
- Loading state — disable buttons, show spinners during requests
What’s next?
Errors are handled. The last piece of polish: loading states throughout your app — spinners, skeleton screens, and disabled buttons that make your app feel professional.Loading states everywhere
Provide consistent loading feedback throughout your full-stack application