API Error Handling
This guide covers common API errors, their causes, and how to handle them effectively in your applications.
Error Response Format
All API errors follow a consistent JSON format:
json
{
"error": {
"message": "Human-readable error description",
"type": "error_type",
"code": "specific_error_code",
"param": "parameter_name",
"details": "Additional error details"
}
}
HTTP Status Codes
Status Code | Description |
---|---|
200 | Success |
400 | Bad Request - Invalid parameters |
401 | Unauthorized - Invalid API key |
403 | Forbidden - Insufficient permissions |
404 | Not Found - Resource doesn't exist |
429 | Too Many Requests - Rate limit exceeded |
500 | Internal Server Error |
502 | Bad Gateway |
503 | Service Unavailable |
Common Error Types
Authentication Errors
Invalid API Key
json
{
"error": {
"message": "Invalid API key provided",
"type": "invalid_request_error",
"code": "invalid_api_key"
}
}
Causes:
- API key is missing or incorrect
- API key format is invalid
- API key has been revoked
Solutions:
- Verify your API key is correct
- Check that the key is properly formatted
- Ensure the key hasn't been revoked
Missing API Key
json
{
"error": {
"message": "You didn't provide an API key",
"type": "invalid_request_error",
"code": "missing_api_key"
}
}
Solutions:
- Include the Authorization header:
Authorization: Bearer YOUR_API_KEY
- Or use the API key header:
api-key: YOUR_API_KEY
Rate Limiting Errors
Rate Limit Exceeded
json
{
"error": {
"message": "Rate limit exceeded",
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"details": "You have exceeded the rate limit. Please wait 60 seconds before making another request."
}
}
Causes:
- Too many requests in a short time period
- Exceeding your plan's rate limits
Solutions:
- Implement exponential backoff
- Reduce request frequency
- Upgrade your plan for higher limits
Quota Exceeded
json
{
"error": {
"message": "You have exceeded your quota",
"type": "quota_exceeded_error",
"code": "quota_exceeded"
}
}
Solutions:
- Check your usage dashboard
- Upgrade your plan
- Wait for quota reset
Request Errors
Invalid Request
json
{
"error": {
"message": "Invalid request format",
"type": "invalid_request_error",
"code": "invalid_request",
"param": "messages"
}
}
Common causes:
- Missing required parameters
- Invalid parameter values
- Malformed JSON
Model Not Found
json
{
"error": {
"message": "Model 'invalid-model' not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model"
}
}
Solutions:
- Use a valid model name (e.g., "deepseek-chat")
- Check available models in the documentation
Context Length Exceeded
json
{
"error": {
"message": "Maximum context length exceeded",
"type": "invalid_request_error",
"code": "context_length_exceeded"
}
}
Causes:
- Input tokens + max_tokens exceeds model limit
- Conversation history is too long
Solutions:
- Reduce input length
- Lower max_tokens parameter
- Implement conversation summarization
Invalid Parameter Value
json
{
"error": {
"message": "Temperature must be between 0 and 2",
"type": "invalid_request_error",
"code": "invalid_parameter_value",
"param": "temperature"
}
}
Server Errors
Internal Server Error
json
{
"error": {
"message": "Internal server error",
"type": "server_error",
"code": "internal_error"
}
}
Solutions:
- Retry the request after a delay
- Contact support if the issue persists
Service Unavailable
json
{
"error": {
"message": "Service temporarily unavailable",
"type": "server_error",
"code": "service_unavailable"
}
}
Solutions:
- Implement retry logic with exponential backoff
- Check status page for service updates
Error Handling Strategies
Retry Logic
Implement exponential backoff for transient errors:
python
import time
import random
from openai import OpenAI
def make_request_with_retry(client, max_retries=3):
for attempt in range(max_retries):
try:
response = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": "Hello"}]
)
return response
except Exception as e:
if attempt == max_retries - 1:
raise e
# Exponential backoff with jitter
wait_time = (2 ** attempt) + random.uniform(0, 1)
time.sleep(wait_time)
Error Classification
Categorize errors for appropriate handling:
python
import openai
def handle_api_error(error):
if isinstance(error, openai.RateLimitError):
print("Rate limit exceeded. Waiting before retry...")
return "retry_after_delay"
elif isinstance(error, openai.AuthenticationError):
print("Authentication failed. Check your API key.")
return "authentication_error"
elif isinstance(error, openai.InvalidRequestError):
print(f"Invalid request: {error}")
return "invalid_request"
elif isinstance(error, openai.APIError):
print(f"API error: {error}")
return "api_error"
else:
print(f"Unexpected error: {error}")
return "unknown_error"
Graceful Degradation
Implement fallback mechanisms:
python
def chat_with_fallback(message):
try:
# Primary model
response = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": message}]
)
return response.choices[0].message.content
except openai.RateLimitError:
# Fallback to cached response or simpler model
return get_cached_response(message) or "I'm currently experiencing high demand. Please try again later."
except Exception as e:
# Generic fallback
return "I'm sorry, I'm having trouble processing your request right now."
Best Practices
1. Implement Proper Error Handling
python
from openai import OpenAI
import openai
import logging
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.deepseek.com/v1"
)
def safe_api_call(messages, **kwargs):
try:
response = client.chat.completions.create(
model="deepseek-chat",
messages=messages,
**kwargs
)
return {"success": True, "data": response}
except openai.RateLimitError as e:
logging.warning(f"Rate limit exceeded: {e}")
return {"success": False, "error": "rate_limit", "retry_after": 60}
except openai.AuthenticationError as e:
logging.error(f"Authentication error: {e}")
return {"success": False, "error": "authentication", "message": str(e)}
except openai.InvalidRequestError as e:
logging.error(f"Invalid request: {e}")
return {"success": False, "error": "invalid_request", "message": str(e)}
except Exception as e:
logging.error(f"Unexpected error: {e}")
return {"success": False, "error": "unknown", "message": str(e)}
2. Monitor and Log Errors
python
import logging
from datetime import datetime
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('api_errors.log'),
logging.StreamHandler()
]
)
def log_api_error(error, request_data):
error_info = {
"timestamp": datetime.now().isoformat(),
"error_type": type(error).__name__,
"error_message": str(error),
"request_data": request_data
}
logging.error(f"API Error: {error_info}")
3. Validate Inputs
python
def validate_chat_request(messages, model="deepseek-chat", **kwargs):
errors = []
# Validate messages
if not messages or not isinstance(messages, list):
errors.append("Messages must be a non-empty list")
for i, message in enumerate(messages):
if not isinstance(message, dict):
errors.append(f"Message {i} must be a dictionary")
elif "role" not in message or "content" not in message:
errors.append(f"Message {i} must have 'role' and 'content' fields")
# Validate temperature
temperature = kwargs.get("temperature")
if temperature is not None and not (0 <= temperature <= 2):
errors.append("Temperature must be between 0 and 2")
# Validate max_tokens
max_tokens = kwargs.get("max_tokens")
if max_tokens is not None and max_tokens <= 0:
errors.append("max_tokens must be positive")
return errors
4. Implement Circuit Breaker
python
import time
from enum import Enum
class CircuitState(Enum):
CLOSED = "closed"
OPEN = "open"
HALF_OPEN = "half_open"
class CircuitBreaker:
def __init__(self, failure_threshold=5, timeout=60):
self.failure_threshold = failure_threshold
self.timeout = timeout
self.failure_count = 0
self.last_failure_time = None
self.state = CircuitState.CLOSED
def call(self, func, *args, **kwargs):
if self.state == CircuitState.OPEN:
if time.time() - self.last_failure_time > self.timeout:
self.state = CircuitState.HALF_OPEN
else:
raise Exception("Circuit breaker is open")
try:
result = func(*args, **kwargs)
self.on_success()
return result
except Exception as e:
self.on_failure()
raise e
def on_success(self):
self.failure_count = 0
self.state = CircuitState.CLOSED
def on_failure(self):
self.failure_count += 1
self.last_failure_time = time.time()
if self.failure_count >= self.failure_threshold:
self.state = CircuitState.OPEN
Error Recovery Patterns
1. Exponential Backoff
python
import time
import random
def exponential_backoff(func, max_retries=3, base_delay=1):
for attempt in range(max_retries):
try:
return func()
except Exception as e:
if attempt == max_retries - 1:
raise e
delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
2. Jittered Retry
python
def jittered_retry(func, max_retries=3, base_delay=1, max_delay=60):
for attempt in range(max_retries):
try:
return func()
except Exception as e:
if attempt == max_retries - 1:
raise e
delay = min(base_delay * (2 ** attempt), max_delay)
jitter = random.uniform(0, delay * 0.1)
time.sleep(delay + jitter)
3. Timeout Handling
python
import signal
from contextlib import contextmanager
@contextmanager
def timeout(seconds):
def timeout_handler(signum, frame):
raise TimeoutError("Operation timed out")
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(seconds)
try:
yield
finally:
signal.alarm(0)
# Usage
try:
with timeout(30): # 30 second timeout
response = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": "Hello"}]
)
except TimeoutError:
print("Request timed out")
Debugging Tips
1. Enable Debug Logging
python
import logging
import openai
# Enable debug logging
logging.basicConfig(level=logging.DEBUG)
openai.log = "debug"
2. Inspect Request/Response
python
import json
def debug_api_call(messages, **kwargs):
print("Request:")
print(json.dumps({
"model": "deepseek-chat",
"messages": messages,
**kwargs
}, indent=2))
try:
response = client.chat.completions.create(
model="deepseek-chat",
messages=messages,
**kwargs
)
print("Response:")
print(json.dumps(response.model_dump(), indent=2))
return response
except Exception as e:
print(f"Error: {e}")
raise e
3. Test Error Scenarios
python
def test_error_scenarios():
# Test invalid API key
try:
invalid_client = OpenAI(api_key="invalid-key")
invalid_client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": "test"}]
)
except openai.AuthenticationError:
print("✓ Invalid API key error handled correctly")
# Test invalid model
try:
client.chat.completions.create(
model="invalid-model",
messages=[{"role": "user", "content": "test"}]
)
except openai.InvalidRequestError:
print("✓ Invalid model error handled correctly")