Skip to main content

Error codes

The YODI API uses standard HTTP status codes and specific error codes to help you diagnose and resolve issues.

HTTP status codes​

CodeStatutDescription
200OKRequête réussie
400Bad RequestParamètres de requête invalides
401UnauthorizedClé API manquante ou invalide
403ForbiddenAccès refusé ou permissions insuffisantes
404Not FoundEndpoint ou ressource introuvable
429Too Many RequestsLimite de taux dépassée
500Internal Server ErrorErreur serveur interne
502Bad GatewayProblème de passerelle
503Service UnavailableService temporairement indisponible

Structure des erreurs​

{
"message": "CODE_ERREUR",
"error": true,
"data": null,
"status": 4XX
}

Champs de l'erreur​

ChampTypeDescription
messagestringCode d'erreur spécifique (ex: INVALID_API_KEY)
errorbooleantrue pour une erreur
datanullToujours null en cas d'erreur
statusintegerCode HTTP (400, 401, 403, 429, 500, etc.)

Types d'erreurs​

invalid_request_error​

Erreurs liées aux paramètres de la requête.

invalid_api_key​

{
"message": "INVALID_API_KEY",
"error": true,
"data": null,
"status": 401
}

Causes :

  • ClĂ© API incorrecte ou malformĂ©e
  • ClĂ© API rĂ©voquĂ©e ou expirĂ©e
  • Format d'autorisation incorrect

Solutions :

  • VĂ©rifiez votre clĂ© API dans le tableau de bord
  • Assurez-vous d'utiliser le format Bearer your_api_key
  • GĂ©nĂ©rez une nouvelle clĂ© si nĂ©cessaire

missing_api_key​

{
"message": "MISSING_API_KEY",
"error": true,
"data": null,
"status": 401
}

Solution :

# Incorrect
response = requests.post("https://api.yodi.tg/v1/chat/completions", json=data)

# Correct
headers = {"Authorization": "Bearer your_api_key_here"}
response = requests.post("https://api.yodi.tg/v1/chat/completions", headers=headers, json=data)

invalid_model​

{
"message": "INVALID_MODEL",
"error": true,
"data": null,
"status": 400
}

Modèles valides :

  • yodi-1
  • yodi-1-32k
  • yodi-embed
  • yodi-code
  • yodi-instruct

context_length_exceeded​

{
"message": "CONTEXT_LENGTH_EXCEEDED",
"error": true,
"data": null,
"status": 400
}

Solutions :

def handle_context_limit(messages, max_tokens=7000):
"""Réduit le contexte si nécessaire"""
# Estimation grossière des tokens
total_tokens = sum(len(msg["content"].split()) * 1.3 for msg in messages)

if total_tokens > max_tokens:
# Garder le message système et les messages récents
system_msgs = [msg for msg in messages if msg["role"] == "system"]
other_msgs = [msg for msg in messages if msg["role"] != "system"]

# Garder seulement les derniers messages
while total_tokens > max_tokens and len(other_msgs) > 2:
other_msgs.pop(0)
total_tokens = sum(len(msg["content"].split()) * 1.3 for msg in system_msgs + other_msgs)

return system_msgs + other_msgs

return messages

# Utilisation
try:
response = client.chat.completions.create(
model="yodi-1",
messages=messages
)
except Exception as e:
if "context_length_exceeded" in str(e):
# Réduire le contexte et réessayer
reduced_messages = handle_context_limit(messages)
response = client.chat.completions.create(
model="yodi-1-32k", # ou utiliser le modèle 32k
messages=reduced_messages
)

invalid_parameter​

{
"message": "INVALID_PARAMETER",
"error": true,
"data": null,
"status": 400
}

Paramètres valides :

  • temperature: 0.0 - 2.0
  • top_p: 0.0 - 1.0
  • max_tokens: 1 - limite du modèle
  • frequency_penalty: -2.0 - 2.0
  • presence_penalty: -2.0 - 2.0

rate_limit_error​

Erreurs liées aux limites de taux.

rate_limit_exceeded​

{
"message": "RATE_LIMIT_EXCEEDED",
"error": true,
"data": null,
"status": 429
}

Gestion avec backoff exponentiel :

import time
import random

def exponential_backoff(func, max_retries=5):
"""Implémente un backoff exponentiel avec jitter"""
for attempt in range(max_retries):
try:
return func()
except Exception as e:
if "rate_limit" in str(e).lower() and attempt < max_retries - 1:
# Calcul du délai avec jitter
base_delay = 2 ** attempt
jitter = random.uniform(0, 1)
delay = base_delay + jitter

print(f"Rate limit atteint, attente {delay:.1f}s (tentative {attempt + 1})")
time.sleep(delay)
else:
raise e

raise Exception("Nombre maximum de tentatives atteint")

# Utilisation
def make_api_call():
return client.chat.completions.create(
model="yodi-1",
messages=[{"role": "user", "content": "Hello"}]
)

response = exponential_backoff(make_api_call)

quota_exceeded​

{
"message": "QUOTA_EXCEEDED",
"error": true,
"data": null,
"status": 429
}

Solutions :

  • VĂ©rifiez votre usage dans le tableau de bord
  • Mettez Ă  niveau votre plan si nĂ©cessaire
  • Optimisez vos requĂŞtes pour rĂ©duire la consommation

server_error​

Erreurs côté serveur.

internal_error​

{
"message": "INTERNAL_ERROR",
"error": true,
"data": null,
"status": 500
}

Gestion :

def robust_api_call(func, max_retries=3):
"""Gère les erreurs serveur avec retry automatique"""
for attempt in range(max_retries):
try:
return func()
except Exception as e:
if any(code in str(e) for code in ["500", "502", "503", "internal_error"]):
if attempt < max_retries - 1:
wait_time = (attempt + 1) * 2
print(f"Erreur serveur, nouvelle tentative dans {wait_time}s...")
time.sleep(wait_time)
continue
raise e

Gestion d'erreurs complète​

Classe de gestion d'erreurs​

import logging
from enum import Enum
from typing import Optional, Callable

class YodiErrorType(Enum):
AUTHENTICATION = "authentication"
RATE_LIMIT = "rate_limit"
VALIDATION = "validation"
SERVER = "server"
NETWORK = "network"

class YodiErrorHandler:
def __init__(self, logger: Optional[logging.Logger] = None):
self.logger = logger or logging.getLogger(__name__)

def classify_error(self, error: Exception) -> YodiErrorType:
"""Classifie le type d'erreur"""
error_str = str(error).lower()

if any(code in error_str for code in ["401", "403", "invalid_api_key", "missing_api_key"]):
return YodiErrorType.AUTHENTICATION
elif any(code in error_str for code in ["429", "rate_limit", "quota"]):
return YodiErrorType.RATE_LIMIT
elif any(code in error_str for code in ["400", "invalid_parameter", "context_length"]):
return YodiErrorType.VALIDATION
elif any(code in error_str for code in ["500", "502", "503", "internal_error"]):
return YodiErrorType.SERVER
else:
return YodiErrorType.NETWORK

def handle_error(self, error: Exception, context: str = "") -> str:
"""Gère une erreur et retourne un message utilisateur"""
error_type = self.classify_error(error)

if error_type == YodiErrorType.AUTHENTICATION:
message = "Erreur d'authentification. Vérifiez votre clé API."
self.logger.error(f"Auth error in {context}: {error}")

elif error_type == YodiErrorType.RATE_LIMIT:
message = "Limite de taux atteinte. Veuillez patienter avant de réessayer."
self.logger.warning(f"Rate limit in {context}: {error}")

elif error_type == YodiErrorType.VALIDATION:
message = f"Paramètres invalides: {error}"
self.logger.error(f"Validation error in {context}: {error}")

elif error_type == YodiErrorType.SERVER:
message = "Erreur serveur temporaire. Réessayez dans quelques instants."
self.logger.error(f"Server error in {context}: {error}")

else:
message = f"Erreur de connexion: {error}"
self.logger.error(f"Network error in {context}: {error}")

return message

# Utilisation
error_handler = YodiErrorHandler()

def safe_api_call(func: Callable, context: str = ""):
"""Appel API avec gestion d'erreurs complète"""
try:
return func(), None
except Exception as e:
error_message = error_handler.handle_error(e, context)
return None, error_message

# Exemple
result, error = safe_api_call(
lambda: client.chat.completions.create(
model="yodi-1",
messages=[{"role": "user", "content": "Hello"}]
),
context="chat_completion"
)

if error:
print(f"Erreur: {error}")
else:
print(f"Succès: {result.choices[0].message.content}")

Décorateur pour retry automatique​

from functools import wraps
import time
import random

def retry_on_error(max_retries=3, backoff_factor=2, retry_codes=None):
"""Décorateur pour retry automatique sur certaines erreurs"""
if retry_codes is None:
retry_codes = ["429", "500", "502", "503", "rate_limit", "internal_error"]

def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
should_retry = any(code in str(e).lower() for code in retry_codes)

if should_retry and attempt < max_retries - 1:
# Calcul du délai avec jitter
delay = (backoff_factor ** attempt) + random.uniform(0, 1)
print(f"Tentative {attempt + 1} échouée, retry dans {delay:.1f}s")
time.sleep(delay)
else:
raise e

return None
return wrapper
return decorator

# Utilisation
@retry_on_error(max_retries=5, backoff_factor=1.5)
def create_completion(messages):
return client.chat.completions.create(
model="yodi-1",
messages=messages
)

Monitoring et alertes​

Système de monitoring​

from collections import defaultdict
from datetime import datetime, timedelta

class ErrorMonitor:
def __init__(self, alert_threshold=10, time_window_minutes=5):
self.errors = defaultdict(list)
self.alert_threshold = alert_threshold
self.time_window = timedelta(minutes=time_window_minutes)

def log_error(self, error_type: str, error_message: str):
"""Enregistre une erreur"""
timestamp = datetime.now()
self.errors[error_type].append({
'timestamp': timestamp,
'message': error_message
})

# Nettoyer les erreurs anciennes
self._cleanup_old_errors(error_type)

# Vérifier les seuils d'alerte
if len(self.errors[error_type]) >= self.alert_threshold:
self._trigger_alert(error_type)

def _cleanup_old_errors(self, error_type: str):
"""Supprime les erreurs trop anciennes"""
cutoff = datetime.now() - self.time_window
self.errors[error_type] = [
error for error in self.errors[error_type]
if error['timestamp'] > cutoff
]

def _trigger_alert(self, error_type: str):
"""Déclenche une alerte"""
count = len(self.errors[error_type])
print(f"🚨 ALERTE: {count} erreurs de type '{error_type}' en {self.time_window.total_seconds()/60:.0f} minutes")

def get_error_summary(self) -> dict:
"""Retourne un résumé des erreurs récentes"""
summary = {}
for error_type, error_list in self.errors.items():
summary[error_type] = {
'count': len(error_list),
'latest': error_list[-1]['timestamp'] if error_list else None
}
return summary

monitor = ErrorMonitor()

def monitored_api_call(func, operation_name="api_call"):
"""Appel API avec monitoring d'erreurs"""
try:
return func()
except Exception as e:
error_type = YodiErrorHandler().classify_error(e).value
monitor.log_error(error_type, str(e))
raise

Debugging et logs​

Configuration de logging avancée​

import logging
import json

class YodiAPILogger:
def __init__(self, log_level=logging.INFO):
self.logger = logging.getLogger("yodi_api")
self.logger.setLevel(log_level)

# Handler pour fichier
file_handler = logging.FileHandler("yodi_api.log")
file_handler.setLevel(logging.DEBUG)

# Handler pour console
console_handler = logging.StreamHandler()
console_handler.setLevel(log_level)

# Format des logs
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

self.logger.addHandler(file_handler)
self.logger.addHandler(console_handler)

def log_request(self, endpoint, params, response_time=None, error=None):
"""Log une requĂŞte API"""
log_data = {
'endpoint': endpoint,
'params': params,
'response_time': response_time,
'error': str(error) if error else None
}

if error:
self.logger.error(f"API Error: {json.dumps(log_data)}")
else:
self.logger.info(f"API Success: {json.dumps(log_data)}")

# Utilisation
api_logger = YodiAPILogger()

def logged_api_call(func, endpoint, params):
"""Appel API avec logging complet"""
start_time = time.time()
try:
result = func()
response_time = time.time() - start_time
api_logger.log_request(endpoint, params, response_time)
return result
except Exception as e:
response_time = time.time() - start_time
api_logger.log_request(endpoint, params, response_time, e)
raise

Prochaines étapes​