Error Handling
This guide covers common errors, their causes, and how to handle them in your application.
400 Bad Request
{
"detail": "Invalid request format"
}
Common Causes:
- Malformed request body or invalid parameters
- Invalid model name (must be one of the supported models)
conversationIdrequired whencontinueGenerateis true- Cannot continue generate on conversation with no previous messages
- Invalid conversation ID format
Example - Invalid Model:
{
"detail": [
{
"type": "literal_error",
"msg": "Input should be 'claude-v4.6-opus', 'claude-v4.6-sonnet', ..."
}
]
}
Solution:
- Validate request body before sending
- Check model name against supported models list
- Ensure required fields are present
- Validate conversation_id format (ULID)
401 Unauthorized
{
"detail": "Invalid API key"
}
Cause:
Missing or incorrect x-api-key header
Solution:
- Verify your API key is correct
- Ensure the
x-api-keyheader is included in the request - Check for typos or extra whitespace in the API key
- Contact AI Commons team if key appears invalid
404 Not Found
During Polling (Normal Behavior):
{
"detail": "Conversation not found"
}
Cause: Conversation is still processing
Action: Continue polling with exponential backoff (this is expected behavior)
Permanent Not Found:
{
"detail": "No conversation found for id: {conversation_id}"
}
Cause: Invalid conversation ID or conversation was deleted
Action: Verify the conversation ID is correct
Message Not Found:
{
"detail": "Message {message_id} not found in conversation {conversation_id}"
}
Cause: Invalid message ID or message doesn't exist
Action: Check the message ID from the conversation's message_map
User Not Found:
{
"detail": "User Not Found."
}
Cause: Invalid user ID (admin endpoints only)
429 Token Limit Exceeded
{
"message": "Token limit exceeded for current monthly window",
"current_usage": 1500000,
"limit": 1000000,
"remaining": 0,
"window_info": {
"window_key": "2026-04",
"days_remaining": 10
}
}
Cause:
Monthly token limit exceeded
Solutions:
- Wait until the next monthly window
- Contact support to increase your token limit
- Monitor token usage via
/token-usageendpoint - Optimize prompts to use fewer tokens
- Use more efficient models for simple tasks
Prevention:
import requests
def check_token_usage():
response = requests.get(
f"{API_URL}/token-usage",
headers={"x-api-key": API_KEY}
)
usage = response.json()
usage_percent = (usage["total_tokens"] / usage["token_limit"]) * 100
if usage_percent > 80:
print("⚠️ Warning: Over 80% of monthly limit used")
return False
return True
# Check before making API calls
if check_token_usage():
create_conversation("Your message")
500 Internal Server Error
Generic Error:
{
"detail": "Internal server error"
}
Processing Failed:
{
"detail": "Conversation processing failed for id: {conversation_id}"
}
DynamoDB Error:
{
"detail": {
"errors": ["Internal server error"]
}
}
Causes:
- Server-side error during processing
- Database connection issues
- Model service unavailable
What to do:
- Retry with exponential backoff
- Check if the issue persists
- Contact support if error continues
Best Practices
1. Validate Input Before Sending
def validate_request(message, model):
# Check model is supported
supported_models = [
'claude-v4.6-opus', 'claude-v4.6-sonnet',
'claude-v4.5-haiku', 'mistral-large-2',
# ... add all supported models
]
if model not in supported_models:
raise ValueError(f"Unsupported model: {model}")
# Check message is not empty
if not message or not message.strip():
raise ValueError("Message cannot be empty")
return True
2. Handle 404 During Polling
def poll_conversation(conversation_id):
interval = 0.3
max_retries = 5
for attempt in range(max_retries):
time.sleep(interval)
response = requests.get(
f"{API_URL}/conversation/{conversation_id}",
headers={"x-api-key": API_KEY}
)
if response.status_code == 200:
return response.json()
elif response.status_code == 404:
# Still processing - apply backoff
interval = min(interval * 1.5, 5.0)
continue
else:
# Other error - stop polling
response.raise_for_status()
3. Implement Exponential Backoff for 5xx Errors
def make_request_with_retry(url, headers, json_data, max_retries=3):
for attempt in range(max_retries):
try:
response = requests.post(url, headers=headers, json=json_data)
if response.status_code >= 500:
if attempt < max_retries - 1:
wait_time = 2 ** attempt # 1s, 2s, 4s
time.sleep(wait_time)
continue
return response
except requests.exceptions.RequestException as e:
if attempt < max_retries - 1:
time.sleep(2 ** attempt)
continue
raise
raise Exception("Max retries exceeded")
4. Log Errors with Context
import logging
logging.basicConfig(level=logging.INFO)
def create_conversation(message, model):
try:
response = requests.post(
f"{API_URL}/conversation",
headers={"x-api-key": API_KEY},
json={"message": {...}, "model": model}
)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
logging.error(
f"API Error: {e.response.status_code} - "
f"{e.response.text} - "
f"Model: {model}, Message length: {len(message)}"
)
raise
5. Monitor Token Usage Proactively
def safe_api_call(func):
"""Decorator to check token usage before API calls"""
def wrapper(*args, **kwargs):
usage = get_token_usage()
usage_percent = (usage["total_tokens"] / usage["token_limit"]) * 100
if usage_percent > 90:
raise Exception("Token limit nearly exceeded")
elif usage_percent > 80:
logging.warning("⚠️ 80% of token limit used")
return func(*args, **kwargs)
return wrapper
@safe_api_call
def create_conversation(message):
# Your API call here
pass
6. Handle Rate Limiting Gracefully
def handle_rate_limit(response):
if response.status_code == 429:
retry_after = response.headers.get('Retry-After', 5)
logging.info(f"Rate limited. Waiting {retry_after}s")
time.sleep(int(retry_after))
return True
return False
Complete Error Handling Example
import requests
import time
import logging
class APIError(Exception):
def __init__(self, status_code, detail):
self.status_code = status_code
self.detail = detail
super().__init__(f"API Error {status_code}: {detail}")
def handle_api_request(url, headers, method="GET",
json_data=None, max_retries=3):
"""Make API request with comprehensive error handling"""
for attempt in range(max_retries):
try:
if method == "GET":
response = requests.get(url, headers=headers, timeout=30)
else:
response = requests.post(url, headers=headers,
json=json_data, timeout=30)
if response.status_code == 200:
return response.json()
elif response.status_code == 400:
raise APIError(400, response.json())
elif response.status_code == 401:
raise APIError(401, {"detail": "Invalid API key"})
elif response.status_code == 404:
if attempt < max_retries - 1:
wait_time = 0.3 * (1.5 ** attempt)
logging.info(f"404 - Retrying in {wait_time:.2f}s...")
time.sleep(wait_time)
continue
else:
raise APIError(404, response.json())
elif response.status_code == 429:
logging.warning("Rate limited - waiting 5s...")
time.sleep(5)
continue
elif response.status_code >= 500:
if attempt < max_retries - 1:
wait_time = 2 ** attempt
logging.warning(f"Server error - retrying in {wait_time}s...")
time.sleep(wait_time)
continue
else:
raise APIError(response.status_code, response.json())
else:
raise APIError(response.status_code, response.json())
except requests.exceptions.Timeout:
if attempt < max_retries - 1:
logging.warning("Timeout - retrying...")
time.sleep(1)
continue
else:
raise APIError(408, {"detail": "Request timeout"})
except requests.exceptions.ConnectionError:
if attempt < max_retries - 1:
logging.warning("Connection error - retrying...")
time.sleep(2)
continue
else:
raise APIError(503, {"detail": "Service unavailable"})
raise APIError(500, {"detail": "Max retries exceeded"})
# Usage
try:
conversation = handle_api_request(
url=f"{API_URL}/conversation/{conversation_id}",
headers={"x-api-key": API_KEY},
method="GET"
)
print(f"Success: {conversation}")
except APIError as e:
if e.status_code == 429:
print("Token limit exceeded")
elif e.status_code == 404:
print("Conversation not found")
else:
print(f"Error {e.status_code}: {e.detail}")
Status Code Summary
| Code | Meaning | Retry? | Action |
|---|---|---|---|
| 200 | Success | No | Process response |
| 202 | Accepted (processing) | No | Start polling |
| 400 | Bad Request | No | Fix request and retry |
| 401 | Unauthorized | No | Check API key |
| 404 | Not Found | Yes (during polling) | Continue polling with backoff |
| 429 | Rate Limited | Yes | Wait and retry |
| 500 | Server Error | Yes | Exponential backoff |