# Network & API Error Patterns Common network and API errors with diagnosis and solutions. ## HTTP Status Errors ### 400 Bad Request ``` HTTP 400 Bad Request {"error": "Bad Request", "message": "Invalid JSON"} ``` **Causes**: 1. Malformed JSON body 2. Missing required fields 3. Invalid field values 4. Wrong Content-Type header **Diagnosis**: ```bash # Validate JSON echo '{"key": "value"}' | jq . # Check request curl -v -X POST https://api.example.com/endpoint \ -H "Content-Type: application/json" \ -d '{"key": "value"}' ``` **Solutions**: ```javascript // Check Content-Type fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', // Not 'text/plain' }, body: JSON.stringify(data), // Not just data }) // Validate before sending if (!data.required_field) { throw new Error('Missing required_field') } ``` --- ### 401 Unauthorized ``` HTTP 401 Unauthorized {"error": "Unauthorized", "message": "Invalid or expired token"} ``` **Causes**: 1. Missing auth token 2. Expired token 3. Invalid token format 4. Wrong auth scheme **Solutions**: ```javascript // Check Authorization header format fetch(url, { headers: { 'Authorization': `Bearer ${token}`, // Note: "Bearer " prefix }, }) // Refresh token if expired async function fetchWithAuth(url) { let response = await fetch(url, { headers: { 'Authorization': `Bearer ${accessToken}` } }) if (response.status === 401) { accessToken = await refreshToken() response = await fetch(url, { headers: { 'Authorization': `Bearer ${accessToken}` } }) } return response } ``` --- ### 403 Forbidden ``` HTTP 403 Forbidden {"error": "Forbidden", "message": "Insufficient permissions"} ``` **Causes**: 1. Authenticated but not authorized 2. Resource access denied 3. Rate limiting 4. IP blocked **Different from 401**: 401 = "Who are you?" 403 = "I know who you are, but no." **Solutions**: - Check user permissions/roles - Verify API key scopes - Check rate limit headers - Verify IP whitelist --- ### 404 Not Found ``` HTTP 404 Not Found {"error": "Not Found", "message": "Resource not found"} ``` **Causes**: 1. Wrong URL/endpoint 2. Resource deleted 3. ID doesn't exist 4. Trailing slash issues **Diagnosis**: ```bash # Check URL is correct curl -I https://api.example.com/users/123 # Try with/without trailing slash curl https://api.example.com/users/ curl https://api.example.com/users ``` **Solutions**: ```javascript // Handle 404 gracefully const response = await fetch(`/api/users/${id}`) if (response.status === 404) { return null // Or throw custom error } return response.json() ``` --- ### 405 Method Not Allowed ``` HTTP 405 Method Not Allowed {"error": "Method Not Allowed", "allowed": ["GET", "POST"]} ``` **Causes**: 1. Using wrong HTTP method 2. Endpoint doesn't support method **Solutions**: ```bash # Check allowed methods curl -I -X OPTIONS https://api.example.com/endpoint # Look for Allow header # Use correct method curl -X POST https://api.example.com/users # Not GET ``` --- ### 429 Too Many Requests ``` HTTP 429 Too Many Requests {"error": "Rate Limited", "retry_after": 60} ``` **Causes**: 1. Rate limit exceeded 2. Too many concurrent requests **Solutions**: ```javascript // Implement exponential backoff async function fetchWithRetry(url, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { const response = await fetch(url) if (response.status === 429) { const retryAfter = response.headers.get('Retry-After') || 60 await sleep(retryAfter * 1000 * (i + 1)) continue } return response } throw new Error('Max retries exceeded') } // Rate limiting in client const limiter = new RateLimiter({ tokensPerInterval: 10, interval: 'second', }) async function limitedFetch(url) { await limiter.removeTokens(1) return fetch(url) } ``` --- ### 500 Internal Server Error ``` HTTP 500 Internal Server Error ``` **Causes**: 1. Server-side bug 2. Unhandled exception 3. Database error 4. Third-party service failure **What you can do**: 1. Check if your request is valid 2. Retry later 3. Report to API provider with request details --- ### 502 Bad Gateway ``` HTTP 502 Bad Gateway ``` **Causes**: 1. Upstream server down 2. Proxy misconfiguration 3. Load balancer issues **Solutions**: - Usually temporary - retry later - Check service status page - Implement retry logic --- ### 503 Service Unavailable ``` HTTP 503 Service Unavailable ``` **Causes**: 1. Server overloaded 2. Maintenance mode 3. Capacity issues **Solutions**: ```javascript // Helper function const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)) // Retry with exponential backoff async function fetchWithBackoff(url) { const maxRetries = 5 for (let i = 0; i < maxRetries; i++) { try { const response = await fetch(url) if (response.status === 503) { await sleep(Math.pow(2, i) * 1000) // 1s, 2s, 4s, 8s, 16s continue } return response } catch (error) { if (i === maxRetries - 1) throw error await sleep(Math.pow(2, i) * 1000) } } throw new Error('Max retries exceeded') } ``` --- ### 504 Gateway Timeout ``` HTTP 504 Gateway Timeout ``` **Causes**: 1. Upstream server too slow 2. Long-running operation 3. Network timeout **Solutions**: - Increase timeout settings - Use async/webhook pattern for long operations - Implement pagination for large responses --- ## Connection Errors ### ECONNREFUSED ``` Error: connect ECONNREFUSED 127.0.0.1:3000 ``` **Causes**: 1. Server not running 2. Wrong port 3. Firewall blocking **Diagnosis**: ```bash # Check if port is listening lsof -i :3000 netstat -an | grep 3000 curl -v http://localhost:3000 ``` **Solutions**: 1. Start the server 2. Check port configuration 3. Check firewall rules --- ### ENOTFOUND ``` Error: getaddrinfo ENOTFOUND api.example.com ``` **Causes**: 1. Invalid hostname 2. DNS resolution failure 3. No internet connection **Diagnosis**: ```bash # Test DNS nslookup api.example.com dig api.example.com ping api.example.com ``` **Solutions**: 1. Check URL spelling 2. Try different DNS (8.8.8.8) 3. Check internet connection 4. Check /etc/hosts file --- ### ETIMEDOUT ``` Error: connect ETIMEDOUT ``` **Causes**: 1. Server not responding 2. Firewall silently dropping 3. Network congestion **Solutions**: ```javascript // Increase timeout const controller = new AbortController() const timeoutId = setTimeout(() => controller.abort(), 30000) try { const response = await fetch(url, { signal: controller.signal }) clearTimeout(timeoutId) return response } catch (error) { if (error.name === 'AbortError') { throw new Error('Request timed out') } throw error } ``` --- ### ECONNRESET ``` Error: read ECONNRESET ``` **Causes**: 1. Server closed connection unexpectedly 2. Network interruption 3. Server crashed **Solutions**: ```javascript // Implement retry logic async function fetchWithRetry(url, retries = 3) { for (let i = 0; i < retries; i++) { try { return await fetch(url) } catch (error) { if (error.code === 'ECONNRESET' && i < retries - 1) { await sleep(1000 * (i + 1)) continue } throw error } } } ``` --- ### SSL/TLS Errors #### UNABLE_TO_VERIFY_LEAF_SIGNATURE ``` Error: unable to verify the first certificate ``` **Causes**: 1. Self-signed certificate 2. Missing intermediate certificate 3. Expired certificate **Solutions**: ```javascript // Development only - disable verification (NOT FOR PRODUCTION) process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' // Better - add CA certificate const https = require('https') const agent = new https.Agent({ ca: fs.readFileSync('ca-cert.pem'), }) fetch(url, { agent }) ``` #### CERT_HAS_EXPIRED ``` Error: certificate has expired ``` **Solutions**: 1. Update server certificate 2. Check system time is correct 3. Update CA certificates: `update-ca-certificates` --- ## CORS Errors ### Access-Control-Allow-Origin ``` Access to fetch at 'https://api.example.com' from origin 'https://myapp.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present ``` **Causes**: 1. Server doesn't allow cross-origin requests 2. Missing CORS headers 3. Credentials mode mismatch **Solutions (Server-side)**: ```javascript // Express.js const cors = require('cors') app.use(cors({ origin: 'https://myapp.com', // Or '*' for all (not recommended) credentials: true, })) // Manual headers app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', 'https://myapp.com') res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE') res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization') res.header('Access-Control-Allow-Credentials', 'true') next() }) ``` **Solutions (Client-side workarounds)**: ```javascript // Use proxy in development // vite.config.js export default { server: { proxy: { '/api': { target: 'https://api.example.com', changeOrigin: true, } } } } // Then fetch from /api instead fetch('/api/endpoint') ``` --- ### Preflight Request Failed ``` Response to preflight request doesn't pass access control check ``` **Causes**: 1. OPTIONS request not handled 2. Missing preflight headers **Solutions**: ```javascript // Handle OPTIONS request app.options('*', cors()) // Express with cors // Or manually app.options('*', (req, res) => { res.header('Access-Control-Allow-Origin', '*') res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS') res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization') res.sendStatus(200) }) ``` --- ## JSON Parsing Errors ### Unexpected token < in JSON ``` SyntaxError: Unexpected token '<', "