Skip to content

API/HTTP Error Fixes -- How to Fix Common API Errors

DodaTech Updated 2026-06-22 6 min read

API errors like 400 Bad Request and 500 Internal Server Error break client-server communication -- this guide shows you how to diagnose and fix the most common HTTP status code errors with request/response analysis and server-side fixes.

What You'll Learn

Why It Matters

REST API errors affect every developer who builds or consumes web services. Understanding HTTP status codes and their fixes helps you debug integrations faster and build more reliable APIs.

Real-World Use

When your frontend app receives a 403 Forbidden or a third-party API returns 429 Too Many Requests, knowing how to interpret the status code and apply the correct fix keeps your application functional.

Common API Errors Table

Error Message / Status Cause Fix
400 Bad Request Malformed request body, missing required fields Validate request payload against API schema
401 Unauthorized Missing or invalid authentication token Include valid Authorization: Bearer <token> header
403 Forbidden Authenticated but lacking permission Check user roles and permissions for the resource
404 Not Found Resource endpoint or ID does not exist Verify the URL path and resource ID
405 Method Not Allowed HTTP method not supported for the endpoint Use the correct HTTP method (GET, POST, PUT, DELETE)
429 Too Many Requests Rate limit exceeded Implement exponential backoff retry logic
500 Internal Server Error Server-side exception or unhandled error Check server logs, add error handling middleware

Step-by-Step Fixes

Fix 1: 400 Bad Request

# bad -- missing required field in request body
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice"}'
# {"error": "Bad Request", "message": "email is required"}
# fixed -- include all required fields
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice", "email": "alice@example.com"}'

Expected output:

{"id": 123, "name": "Alice", "email": "alice@example.com"}

Fix 2: 401 Unauthorized

# bad -- no auth token provided
curl https://api.example.com/profile
# {"error": "Unauthorized", "message": "Missing authentication token"}
# fixed -- include Bearer token
TOKEN="eyJhbGciOiJIUzI1NiIs..."
curl -H "Authorization: Bearer $TOKEN" https://api.example.com/profile

Expected output:

{"id": 123, "name": "Alice", "email": "alice@example.com"}

Fix 3: 404 Not Found

# bad.py -- wrong endpoint or ID
import requests

response = requests.get("https://api.example.com/users/99999")
print(response.status_code)  # 404
print(response.json())       # {"error": "User not found"}
# fixed.py -- verify the resource exists first
import requests

user_id = 99999
# Check if user exists
response = requests.get(f"https://api.example.com/users/{user_id}")
if response.status_code == 404:
    print(f"User {user_id} does not exist")
elif response.status_code == 200:
    print(response.json())

Expected output:

User 99999 does not exist

Fix 4: 405 Method Not Allowed

# bad -- using wrong HTTP method
curl -X PUT https://api.example.com/users/123
# {"error": "Method Not Allowed", "message": "Supported methods: GET, DELETE"}
# fixed -- use a supported method
curl -X GET https://api.example.com/users/123

Expected output:

{"id": 123, "name": "Alice", "email": "alice@example.com"}

Fix 5: 429 Too Many Requests

# bad -- hitting rate limit
for i in {1..100}; do
  curl -s https://api.example.com/data
done
# {"error": "Too Many Requests", "retry_after": 60}
# fixed.py -- implement exponential backoff
import requests
import time

def fetch_with_retry(url, max_retries=5):
    for attempt in range(max_retries):
        response = requests.get(url)
        if response.status_code == 429:
            wait = int(response.headers.get("Retry-After", 2 ** attempt))
            print(f"Rate limited, waiting {wait}s...")
            time.sleep(wait)
            continue
        return response
    return response

result = fetch_with_retry("https://api.example.com/data")
print(result.status_code)

Expected output:

Rate limited, waiting 1s...
Rate limited, waiting 2s...
200

Fix 6: 500 Internal Server Error

// bad -- server has unhandled exception
fetch("https://api.example.com/users/123")
  .then(res => res.json())
  .then(data => console.log(data))
  // {"error": "Internal Server Error"}
// fixed -- add proper error handling and logging on server side
// Express.js example
app.get("/api/users/:id", async (req, res) => {
    try {
        const user = await db.findUser(req.params.id);
        if (!user) {
            return res.status(404).json({ error: "User not found" });
        }
        res.json(user);
    } catch (err) {
        console.error("Error fetching user:", err);
        res.status(500).json({ error: "Internal Server Error" });
    }
});

Expected output:

{"id": 123, "name": "Alice", "email": "alice@example.com"}

API Error Diagnosis Flowchart

flowchart TD
    A[API Error Detected] --> B{HTTP Status Code?}
    B -->|4xx Client Error| C{Which Code?}
    C -->|400| D[Check request body and params]
    C -->|401| E[Check auth token]
    C -->|403| F[Check user permissions]
    C -->|404| G[Verify resource URL and ID]
    C -->|405| H[Use correct HTTP method]
    C -->|429| I[Implement retry with backoff]
    B -->|5xx Server Error| J{Which Code?}
    J -->|500| K[Check server logs for exceptions]
    J -->|502| L[Check upstream services]
    J -->|503| M[Service overloaded -- scale up]
    D --> N[Error Resolved]
    E --> N
    F --> N
    G --> N
    H --> N
    I --> N
    K --> N
    L --> N
    M --> N

Prevention Tips

  • Use OpenAPI/Swagger specifications to document all request bodies and parameters
  • Implement centralized error handling middleware in your API framework
  • Always validate request payloads with a schema validator (Joi, Pydantic, Zod)
  • Use proper HTTP methods: GET for reads, POST for creates, PUT for updates, DELETE for deletions
  • Implement rate limiting with meaningful Retry-After headers on the server
  • Log all 5xx errors with full stack traces for debugging
  • Add health check endpoints for monitoring and load balancer configuration

Practice Questions

  1. What is the difference between 401 Unauthorized and 403 Forbidden? Answer: 401 means the client is not authenticated (no valid token). 403 means the client is authenticated but does not have permission to access the resource.

  2. How do you handle a 429 Too Many Requests error in client code? Answer: Implement exponential backoff: wait 1s, 2s, 4s, 8s between retries, reading the Retry-After header if present.

  3. What causes a 405 Method Not Allowed error? Answer: The client used an HTTP method that the server does not support for that endpoint. Check the API documentation for supported methods.

  4. How do you debug a 500 Internal Server Error? Answer: Check the server application logs for unhandled exceptions, add try-catch blocks around risky operations, and use logging middleware.

  5. Challenge: Write a Python function that makes an API request with automatic handling of 401 (refresh token), 429 (exponential backoff), and 5xx (retry up to 3 times) status codes, with a configurable maximum retry count. Answer:

    import requests
    import time
    from functools import wraps
    
    def resilient_api_call(max_retries=3, base_delay=1):
        def decorator(func):
            @wraps(func)
            def wrapper(*args, **kwargs):
                for attempt in range(max_retries):
                    response = func(*args, **kwargs)
                    if response.status_code == 200:
                        return response
                    elif response.status_code == 401:
                        print("Refreshing token...")
                        new_token = refresh_auth_token()
                        kwargs["headers"] = kwargs.get("headers", {})
                        kwargs["headers"]["Authorization"] = f"Bearer {new_token}"
                    elif response.status_code == 429:
                        wait = int(response.headers.get("Retry-After", base_delay * (2 ** attempt)))
                        print(f"Rate limited, waiting {wait}s...")
                        time.sleep(wait)
                    elif response.status_code >= 500:
                        if attempt == max_retries - 1:
                            raise Exception(f"API failed after {max_retries} retries")
                        time.sleep(base_delay * (2 ** attempt))
                    else:
                        return response
                return response
            return wrapper
        return decorator
    
    def refresh_auth_token():
        return "new_token_here"
    
    @resilient_api_call(max_retries=3)
    def call_api(url, headers=None):
        return requests.get(url, headers=headers)
    
    result = call_api("https://api.example.com/data")
    print(result.status_code)
    

Quick Reference

Status Meaning Quick Fix
400 Bad Request Validate request body format and required fields
401 Unauthorized Add valid Bearer token to Authorization header
403 Forbidden Check user role and resource permissions
404 Not Found Verify URL path and resource ID correctness
405 Method Not Allowed Use the correct HTTP method for the endpoint
429 Too Many Requests Implement exponential backoff retry logic
500 Internal Server Error Check server logs and add error handling

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro