Files
wehub-resource-sync bb5c75ce05
Component Security Validation / Security Audit (push) Has been cancelled
Deploy to Cloudflare Pages / deploy (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:38:58 +08:00

12 KiB

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:

# 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:

// 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:

// 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:

# 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:

// 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:

# 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:

// 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:

// 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:

# 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:

# 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:

// 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:

// 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:

// 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):

// 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):

// 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:

// 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 '<', "<!DOCTYPE "... is not valid JSON

Causes:

  1. Server returned HTML instead of JSON (error page, 404)
  2. Wrong endpoint
  3. Auth redirect

Diagnosis:

const response = await fetch(url)
console.log('Status:', response.status)
console.log('Content-Type:', response.headers.get('content-type'))
const text = await response.text()
console.log('Body:', text.substring(0, 200))

Solutions:

// Check response before parsing
const response = await fetch(url)

if (!response.ok) {
  const text = await response.text()
  throw new Error(`HTTP ${response.status}: ${text}`)
}

const contentType = response.headers.get('content-type')
if (!contentType?.includes('application/json')) {
  throw new Error(`Expected JSON, got ${contentType}`)
}

return response.json()

Unexpected end of JSON input

SyntaxError: Unexpected end of JSON input

Causes:

  1. Empty response body
  2. Truncated response
  3. Network interruption

Solutions:

// Check for empty response
const text = await response.text()
if (!text) {
  return null  // Or default value
}
return JSON.parse(text)

Quick Reference Table

Error Category Quick Fix
400 Bad Request Client Check JSON format, Content-Type
401 Unauthorized Auth Check token, refresh if expired
403 Forbidden Auth Check permissions, rate limits
404 Not Found Client Verify URL, check resource exists
429 Too Many Requests Rate Limit Implement backoff, reduce requests
500 Internal Server Error Server Retry, report to provider
503 Service Unavailable Server Retry with exponential backoff
ECONNREFUSED Connection Start server, check port
ENOTFOUND DNS Check hostname, DNS settings
ETIMEDOUT Timeout Increase timeout, check network
CORS blocked Browser Add CORS headers server-side
Unexpected token < Parse Check response is JSON not HTML