HTTP Status Codes Explained: What Every 404, 301, and 500 Really Means
From 200 OK to 503 Service Unavailable, HTTP status codes tell the story of every web request. This guide decodes every important status code with real-world examples and debugging tips.
HTTP Status Codes Explained: What Every 404, 301, and 500 Really Means
Every time you load a webpage, your browser makes dozens of HTTP requests. Each response includes a three-digit status code that tells you what happened. Most people only know 404 — but understanding all the codes makes you a better developer, debugger, and API designer.
This guide covers every status code you'll encounter in practice, with real-world examples, debugging tips, and how they impact SEO.
The Five Categories
| Range | Category | Meaning |
|---|---|---|
| 1xx | Informational | Request received, continuing |
| 2xx | Success | Request succeeded |
| 3xx | Redirection | Further action needed |
| 4xx | Client Error | You made a mistake |
| 5xx | Server Error | The server made a mistake |
2xx Success — All Good
200 OK
The standard success response.
GET /api/users → 200 OK
201 Created
A new resource was successfully created.
POST /api/users → 201 Created
204 No Content
Success, but there's nothing to return.
DELETE /api/users/123 → 204 No Content
Quick Reference
| Code | Meaning | When Used |
|---|---|---|
| 200 | OK | GET, PUT success |
| 201 | Created | POST success |
| 202 | Accepted | Async processing started |
| 204 | No Content | DELETE success |
3xx Redirection — Go Somewhere Else
301 Moved Permanently
The resource has a new permanent URL. Search engines transfer SEO value to the new URL.
GET /old-page → 301 Moved Permanently
Location: /new-page
SEO impact: Link equity passes to the new URL. Use this when permanently moving content.
302 Found (Temporary Redirect)
The resource is temporarily at a different URL.
GET /dashboard → 302 Found
Location: /login
SEO impact: Link equity does NOT pass. Use for temporary redirects.
304 Not Modified
The cached version is still valid. No data transferred — saves bandwidth.
GET /styles.css
If-None-Match: "abc123"
→ 304 Not Modified
307 vs 308
| Code | Method Preserved? | Permanent? |
|---|---|---|
| 307 | ✅ Yes | ❌ No (temporary) |
| 308 | ✅ Yes | ✅ Yes (permanent) |
Note: 301 and 302 may change POST to GET. Use 307/308 if you need to preserve the HTTP method.
4xx Client Error — Your Fault
400 Bad Request
The server can't understand your request.
Common causes:
- Malformed JSON body
- Missing required parameters
- Invalid data types
// POST /api/users
{"name": 123} // name should be a string
→ 400 Bad Request
401 Unauthorized
You need to authenticate first.
GET /api/profile
→ 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
Note: Despite the name, it means "unauthenticated" — you haven't proven who you are.
403 Forbidden
You're authenticated, but you don't have permission.
GET /api/admin/users
Authorization: Bearer user-token
→ 403 Forbidden
401 vs 403:
- 401 = "I don't know who you are" (login first)
- 403 = "I know who you are, but you can't access this"
404 Not Found
The resource doesn't exist.
GET /api/users/999
→ 404 Not Found
SEO tip: Don't redirect all 404s to the homepage. Google treats this as a soft 404. Either return a real 404 with helpful content, or redirect only if there's a relevant replacement page.
405 Method Not Allowed
The URL exists, but this HTTP method isn't supported.
DELETE /api/users/123
→ 405 Method Not Allowed
Allow: GET, POST
429 Too Many Requests
You've hit the rate limit.
GET /api/data
→ 429 Too Many Requests
Retry-After: 60
4xx Quick Reference
| Code | Meaning | Fix |
|---|---|---|
| 400 | Bad Request | Check request format |
| 401 | Unauthorized | Add authentication |
| 403 | Forbidden | Check permissions |
| 404 | Not Found | Check the URL |
| 405 | Method Not Allowed | Use correct HTTP method |
| 408 | Request Timeout | Retry with backoff |
| 413 | Payload Too Large | Reduce request size |
| 429 | Too Many Requests | Slow down, respect rate limits |
5xx Server Error — Server's Fault
500 Internal Server Error
Something went wrong on the server, but the server can't be more specific.
Common causes:
- Unhandled exceptions
- Database connection failures
- Configuration errors
502 Bad Gateway
The server acting as a gateway received an invalid response from upstream.
Common causes:
- Backend server crashed
- Load balancer misconfiguration
- DNS issues
503 Service Unavailable
The server is temporarily down (overloaded or maintenance).
→ 503 Service Unavailable
Retry-After: 3600
504 Gateway Timeout
The upstream server didn't respond in time.
Common causes:
- Slow database queries
- External API timeouts
- Network issues between servers
5xx Quick Reference
| Code | Meaning | Who to Blame |
|---|---|---|
| 500 | Internal Server Error | Backend code |
| 502 | Bad Gateway | Upstream server |
| 503 | Service Unavailable | Overloaded/maintenance |
| 504 | Gateway Timeout | Slow upstream |
Handling Status Codes in JavaScript
When working with the Fetch API, status codes aren't thrown as errors — you must check them manually:
// Basic error handling
async function fetchData(url) {
const response = await fetch(url);
if (!response.ok) {
// response.ok is true for 200-299
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
}
// Detailed error handling by status
async function apiCall(url, options = {}) {
const response = await fetch(url, options);
switch (response.status) {
case 200:
case 201:
return await response.json();
case 400:
throw new Error('Invalid request — check your input');
case 401:
throw new Error('Please log in');
case 403:
throw new Error('You don\'t have permission');
case 404:
throw new Error('Resource not found');
case 429:
const retryAfter = response.headers.get('Retry-After');
throw new Error(`Rate limited. Retry after ${retryAfter}s`);
case 500:
throw new Error('Server error — try again later');
case 503:
throw new Error('Service unavailable — try again later');
default:
throw new Error(`Unexpected status: ${response.status}`);
}
}
// Retry with exponential backoff for 5xx errors
async function fetchWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url);
if (response.status >= 500 && i < maxRetries - 1) {
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
continue;
}
return response;
} catch (err) {
if (i === maxRetries - 1) throw err;
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
}
}
}
API Design: Choosing the Right Status Code
When building APIs, choosing correct status codes matters for client experience:
For successful operations:
200for GET/PUT that returns data201for POST that creates a resource204for DELETE or operations with no response body
For errors, be specific:
400for validation errors (include field-level details)401when no authentication is provided403when authenticated but lacking permission404when the resource doesn't exist409for conflicts (e.g., duplicate email)422for semantically invalid data429for rate limiting (includeRetry-Afterheader)500only for truly unexpected errors
Response body for errors:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input data",
"details": [
{ "field": "email", "message": "Must be a valid email address" },
{ "field": "age", "message": "Must be a positive number" }
]
}
}
Status Codes and SEO
| Code | SEO Impact |
|---|---|
| 200 | ✅ Indexed normally |
| 301 | ✅ Link equity transferred |
| 302 | ⚠️ Temporary, no equity transfer |
| 404 | ❌ Removed from index eventually |
| 410 | ❌ Removed from index faster |
| 5xx | ❌ Crawling paused if persistent |
Debugging Status Codes
Browser DevTools
- Open DevTools (F12)
- Go to Network tab
- Reload the page
- Click any request to see its status code and response
cURL
# See status code only
curl -s -o /dev/null -w "%{http_code}" https://example.com
# See headers
curl -I https://example.com
Try It Yourself
Need to check what status code a URL returns? Our HTTP Status Code Checker lets you test any URL and see its response code, headers, and redirect chain.
Summary
- 2xx = success, everything worked
- 3xx = redirect, go somewhere else
- 4xx = client error, fix your request
- 5xx = server error, not your fault
- 301 for permanent moves (SEO-friendly)
- 404 for truly missing pages
- Always check the Network tab when debugging
- Handle errors gracefully in your JavaScript — check
response.ok - Be specific in API error responses — help clients fix their requests
HTTP status codes are the universal language of the web. Understanding them makes you a better developer, debugger, and SEO practitioner.
Need to check what status code a URL returns? Our HTTP Status Code Checker lets you test any URL and see its response code, headers, and redirect chain.
Try It Yourself
Put what you've learned into practice with our free online tools.
Related Articles
JWT Decoding Tutorial: How to Read and Debug JSON Web Tokens
Learn how to decode JWT tokens, understand their structure, debug authentication issues, and implement JWT security best practices in your applications.
Base64 Encoding Explained: A Complete Guide for Developers
Learn everything about Base64 encoding, when to use it, common use cases, and how to encode and decode Base64 strings in JavaScript, Python, and more.
Getting Started with JSON: A Complete Guide for Developers
Learn the fundamentals of JSON format, how to work with it, and best practices for developers building modern web applications.