TL;DR: HTTP status codes are three-digit numbers that every API response includes. 2xx means success. 3xx means redirect. 4xx means the client (you) made an error. 5xx means the server made an error. The specific number tells you exactly what went wrong and where to look to fix it.
Why AI Coders Need to Know This
When you build with AI tools and your app makes API calls — to Stripe, to a weather API, to your own backend — things go wrong. The most common symptom is a response coming back that isn't what you expected. The error might surface as a broken UI, a silent failure, or an angry red line in your browser's Network tab.
HTTP status codes are the server's way of telling you exactly what happened. Not approximately. Exactly. A 401 means authentication is missing. A 404 means the URL doesn't exist. A 429 means you're being rate-limited. Each code is a specific diagnosis, not a vague error message.
AI tools generate code that makes API calls constantly — fetching data, posting forms, authenticating users, processing payments. When that code fails, the status code is usually the first and most useful clue. Developers who know the status code system debug in minutes. Developers who don't know it spend hours guessing.
This guide covers every status code family and the specific codes you'll actually encounter as a vibe coder. By the end, you'll be able to look at any API error and immediately know whether the problem is in your code, your credentials, your data, or the server itself.
Real Scenario
You've built an app that calls an external API. You asked Claude Code to write the fetch logic, and the response handler looks reasonable. But when you test it, the API isn't returning what you expected. You open the browser DevTools Network tab and see this:
⚠️ The Situation
POST https://api.example.com/v1/data
Status: 401 Unauthorized
Response: {"error": "Invalid API key"}
You paste this into your AI tool:
Prompt I Would Type
My API call is returning a 401 Unauthorized error with the message "Invalid API key."
Here's the fetch code AI generated:
fetch('https://api.example.com/v1/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + apiKey
},
body: JSON.stringify({ query: userInput })
})
The API key is stored in my .env file as API_KEY.
What does 401 mean and what's the most likely cause here?
The AI will explain: a 401 means your request reached the server but authentication failed. The most likely cause is that apiKey is undefined — which means the environment variable isn't being loaded correctly into the JavaScript context. It will suggest checking whether you're using process.env.API_KEY (Node.js), import.meta.env.VITE_API_KEY (Vite), or the equivalent for your framework.
That's a 30-second debug because you knew what 401 meant. Without that knowledge, you might spend an hour rewriting the fetch logic when the problem was just a missing environment variable prefix.
The Five Status Code Families
Every HTTP status code falls into one of five families, determined by the first digit. Learning the families is more valuable than memorizing individual codes — once you know the family, you know where to look for the problem.
There's also a 1xx family (informational) that you'll almost never encounter in practice as a vibe coder, so we'll skip it.
The most important distinction for debugging is 4xx vs 5xx. A 4xx error means the problem is in your request — your code, your credentials, your data. Fix it by changing what you're sending. A 5xx error means the problem is on the server — there's usually nothing you can do except wait, retry, or report it.
The Codes You'll Actually See
There are 60+ official HTTP status codes, but in practice, you'll encounter about a dozen of them regularly. Here are all of them, explained for real-world vibe coding context.
2xx — Success Codes
The most common success code. The request was received, understood, and processed successfully. The response body contains what you asked for. If you're fetching data and get a 200, everything worked.
The request succeeded and a new resource was created as a result. You'll see 201 when you POST to create a new record — a new user, a new order, a new blog post. The response body usually includes the created object with its new ID.
The request succeeded but there's nothing to return. Common after DELETE requests or PUT updates where the server acknowledges success but doesn't send back the updated data. Your code should handle 204 by not trying to parse a response body — there isn't one.
3xx — Redirect Codes
The resource has a new permanent URL. The response includes a Location header with the new address. Browsers and fetch clients follow this automatically. You'll see 301 most often when sites migrate from HTTP to HTTPS, or when URLs are restructured.
Similar to 301, but temporary — the resource is at a different URL for now, but the original URL should be used for future requests. Less common in APIs, more common in web app redirects (like after a login form submission).
4xx — Client Error Codes
This is the family you'll debug most often. All 4xx errors mean you sent something the server couldn't or wouldn't process. The fix is always in your code, data, or credentials.
The server couldn't understand the request because of invalid syntax or malformed data. Common causes: JSON that isn't valid JSON, a required field missing from the request body, an incorrect data type (sending a string where a number is expected). Fix it by checking what the API expects and comparing it to what you're sending.
The server requires authentication and it's missing or invalid. Your API key, token, or credentials aren't being sent correctly — or they're wrong. 401 answers the question: "Who are you?" Fix it by checking that your credentials are loaded correctly and being included in the request headers.
Authentication worked, but you don't have permission to access this resource. The server knows who you are — you just aren't allowed to do this. Common causes: your API key doesn't have the right scopes, you're trying to access another user's data, or your account tier doesn't include this feature.
The URL doesn't exist. Either the resource genuinely doesn't exist (you deleted a record and then tried to fetch it), the URL path is wrong (typo, missing version prefix, wrong endpoint), or the resource hasn't been created yet. Check the URL carefully — AI-generated fetch calls sometimes use slightly wrong endpoint paths.
The request format was correct, but the data itself is invalid. The server understood what you were trying to do but couldn't do it because the data doesn't meet validation rules. Example: a form submission where the email field isn't a valid email, a number is outside the accepted range, or a required field is empty. The response body usually includes field-specific validation errors.
You've exceeded the rate limit — making requests faster than the API allows. The response usually includes a Retry-After header telling you how many seconds to wait before trying again. Fix it by slowing down requests, adding delays between calls, or implementing exponential backoff. This is especially common when AI-generated code makes API calls in a loop.
5xx — Server Error Codes
5xx errors mean the server failed. Your request was usually valid — the server just couldn't fulfill it. You can't fix these by changing your code alone.
Something crashed on the server. It's a catch-all for unexpected server failures — unhandled exceptions, database errors, null pointer issues in the server code. If this is your own API, check your server logs. If it's a third-party API, check their status page. Sometimes they'll resolve themselves; sometimes you need to report it.
A server (acting as a gateway or proxy) received an invalid response from an upstream server. Common when a load balancer or nginx gets a bad response from the application server behind it. Usually indicates a deployment issue, a crashed application server, or a misconfigured infrastructure. Transient — often resolves with a retry.
The server is currently unable to handle requests. Common causes: the server is overloaded, it's down for maintenance, or it just crashed. 503 is explicitly temporary — the server is saying "try again later." Check the API's status page. If it's your own server, check that the application process is running.
What AI Generated
When you ask an AI tool to build an API call with proper error handling, it will typically generate something like this. Understanding the status codes it checks for is exactly what makes this code readable:
// Realistic AI-generated fetch with status code handling
// Ask AI: "Write a fetch function for the /api/users endpoint with full error handling"
async function fetchUser(userId) {
try {
const response = await fetch(`/api/users/${userId}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${getAuthToken()}`, // Include auth token
'Content-Type': 'application/json'
}
});
// Check if the response was successful (2xx range)
if (!response.ok) {
// response.status gives us the numeric code
// response.statusText gives the text description
if (response.status === 401) {
// Authentication failed — redirect to login
redirectToLogin();
return;
}
if (response.status === 403) {
// Authenticated but no permission
throw new Error('You do not have permission to view this user.');
}
if (response.status === 404) {
// User doesn't exist
return null; // Return null and let the UI handle "not found"
}
if (response.status === 429) {
// Rate limited — read the retry time from the header
const retryAfter = response.headers.get('Retry-After') || '60';
throw new Error(`Rate limited. Try again in ${retryAfter} seconds.`);
}
if (response.status >= 500) {
// Server error — not our fault but we need to handle it
throw new Error('Server error. Please try again later.');
}
// Any other error code we didn't handle specifically
throw new Error(`Request failed with status ${response.status}`);
}
// 200-299: parse and return the JSON body
const data = await response.json();
return data;
} catch (error) {
// Network errors (no internet, DNS failure, CORS) also land here
console.error('Fetch failed:', error.message);
throw error; // Re-throw so the caller can decide how to handle it
}
}
This is solid, practical error handling. The key pattern is checking response.ok first (which is true for any 2xx code), then handling specific error codes based on what each one actually means for your application logic.
Understanding Each Part
response.ok
response.ok is a JavaScript Fetch API shortcut. It's true if the status code is between 200–299, and false for everything else. It's the fastest way to check "did this request succeed?" without reading the specific number.
response.status
response.status is the actual number — 200, 401, 404, etc. Use this when you need to handle specific codes differently. Not every 4xx error means the same thing to your application: a 404 might be "show empty state," while a 401 might be "redirect to login."
response.headers.get('Retry-After')
Some status codes include extra information in response headers. 429 (rate limited) commonly includes a Retry-After header telling you exactly how long to wait. 301/302 redirects include a Location header with the new URL. Reading headers is how you get the full picture from a status code.
try/catch around fetch
A try/catch block is necessary even with good status code handling because not all failures produce a status code. Network errors (no internet connection, DNS failure, request timeout, CORS blocking) throw JavaScript exceptions before a response is received — there's no status code at all. The catch block handles these network-level failures.
What AI Gets Wrong About HTTP Status Codes
Treating all errors the same
AI often generates error handling that catches everything and shows a generic "something went wrong" message. That's better than nothing but it hides useful information. A user who gets a 401 should see "please log in again," not "an error occurred." A user who gets a 429 should know to wait. Handle specific codes specifically.
Not checking response.ok before parsing JSON
A classic AI mistake: calling response.json() before checking whether the request succeeded. If the response is a 404 and the body contains HTML (like a custom error page), response.json() throws a parse error that has nothing to do with the original problem. Always check response.ok or response.status first.
// ❌ AI sometimes generates this — dangerous
const data = await fetch('/api/user/123').then(r => r.json());
// ✅ Correct pattern — check status before parsing
const response = await fetch('/api/user/123');
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json();
Confusing 401 and 403
AI occasionally uses these interchangeably in documentation comments, but they mean very different things for your application. 401 = you need to authenticate (send credentials). 403 = you're authenticated but not allowed (check permissions). The fix is different for each. Make sure AI-generated error messages reflect this distinction.
No handling for 429 rate limits
AI tools often write API calls without rate limit handling, especially when generating code that makes multiple calls in sequence. If you're calling an external API in a loop or in batch, always ask the AI to add rate limit handling with exponential backoff. Getting rate-limited without retry logic means your app silently fails on roughly half its requests.
Swallowing 5xx errors silently
Code that catches 500/502/503 and returns null without logging or alerting makes production debugging very hard. When a server error happens, your application should at minimum log it, ideally with the full response body. Silence doesn't help anyone find the root cause.
How to Debug API Status Codes With AI
The Network Tab is your best tool
Open Chrome DevTools → Network tab → look for red requests. Click a failed request and examine:
- Status — the code itself
- Headers → Request Headers — what you sent (including Authorization)
- Headers → Response Headers — what the server sent back
- Preview / Response — the actual error body (often contains a helpful message)
The response body is frequently more useful than the status code alone. {"error": "Invalid API key provided"} tells you much more than just "401".
Cursor tips
- Copy the full Network tab entry (status + request headers + response body) and paste it into Cursor Chat. Ask: "What does this API response tell me about why my request failed, and how do I fix it?"
- Ask Cursor to add
console.log(response.status, await response.text())to any failing fetch call — this surfaces the full error body in your browser console instantly. - Use
@codebaseto find every place you're calling a specific API, then ask Cursor to audit all of them for missing status code handling.
Windsurf tips
- Ask Cascade to "add comprehensive error handling to all fetch calls in this project, handling 401, 403, 404, 422, 429, and 5xx codes appropriately."
- For 401 debugging, ask Windsurf to trace where the auth token comes from and verify it's being passed to the request correctly.
Claude Code tips
- Claude Code can read your actual code and simulate what different status code responses would trigger. Ask: "If this endpoint returns a 422 with the field validation errors, what does my current code do with that response? Show me the execution path."
- Ask Claude Code to write a test that specifically triggers each error code to verify your handling works correctly.
Debug Rule of Thumb
4xx = fix your code. 5xx = check the server. 401 = check credentials. 403 = check permissions. 429 = slow down. 404 = check the URL. Memorize this and you'll debug most API issues in under two minutes.
Quick reference: status code → where to look
Is the code 4xx?
The problem is in your request. Check: is the URL correct? Are credentials included? Is the request body valid? Are required fields present? Is data in the right format?
Is the code 5xx?
The problem is on the server. Check: the API's status page, your server logs (if it's your API), and whether a retry resolves it. Report to the API provider if it persists.
Got a 401?
Check that credentials exist (not undefined), are in the right header format (Bearer token vs ApiKey key), and haven't expired.
Got a 422?
Check the response body for field-specific validation errors. Compare your request body to the API documentation for required fields and formats.
What to Learn Next
HTTP status codes are part of the broader HTTP and REST API ecosystem. These articles go deeper on the concepts that surround status codes:
- What Is a REST API? — how REST APIs work, including how status codes fit into the HTTP request/response cycle
- What Is an API? — the foundational concept of APIs before getting into REST specifics
- What Is Async/Await? — the JavaScript syntax used to write the fetch calls that produce these status codes
- What Is an Environment Variable? — how to handle API keys correctly so you never see a 401 from leaked credentials
- Security Basics for AI Coders — including authentication patterns that prevent 401/403 errors from becoming security vulnerabilities
FAQ
A 401 Unauthorized error means the server received your request but requires authentication that is missing or invalid. You need to include a valid API key, token, or login credentials. 401 is about authentication (who are you?), not authorization (what can you do?).
A 401 means you haven't proven who you are yet — authentication is missing. A 403 means the server knows who you are but won't let you access the resource — you don't have permission. Fix 401 by adding credentials. Fix 403 by checking your account's permissions or access tier.
A 500 error means something crashed on the server — it's a server-side bug, not a problem with your request. Common causes include unhandled exceptions in application code, database connection failures, misconfigured environment variables, or out-of-memory conditions. Check your server logs.
A 422 Unprocessable Entity error means the server understood your request format but couldn't process it because the data itself is invalid. Common examples: a required field is missing, an email address is malformed, or a value is outside the allowed range. Check the response body for field-specific error messages.
A 429 Too Many Requests error means you've exceeded the API's rate limit — you're making requests faster than the server allows. The response usually includes a Retry-After header telling you how long to wait. Implement exponential backoff in your code to handle this gracefully.