AI Commons

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)
  • conversationId required when continueGenerate is 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-key header 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-usage endpoint
  • 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