Gestion d'erreurs et codes HTTP
Gestion d’erreurs et codes HTTP
En production, les erreurs sont inévitables. Comprendre les codes HTTP retournés par l’API et savoir les gérer correctement est essentiel pour construire des applications robustes.
Les codes HTTP de l’API OpenAI
L’API retourne des codes HTTP standards pour indiquer le résultat de chaque requête :
from openai import OpenAI
from openai import (
APIError,
AuthenticationError,
BadRequestError,
RateLimitError,
APIConnectionError,
InternalServerError,
PermissionDeniedError,
NotFoundError,
UnprocessableEntityError,
)
client = OpenAI()
401 — AuthenticationError
try:
# Clé API invalide ou manquante
bad_client = OpenAI(api_key="sk-invalid")
bad_client.responses.create(
model="gpt-5.3",
input="Test"
)
except AuthenticationError as e:
print(f"Code : {e.status_code}") # 401
print(f"Message : {e.message}")
# Action : vérifier la clé API, la régénérer si nécessaire
400 — BadRequestError
try:
# Paramètres invalides
client.responses.create(
model="gpt-5.3",
input="Test",
temperature=5.0 # Valeur invalide (max 2.0)
)
except BadRequestError as e:
print(f"Code : {e.status_code}") # 400
print(f"Message : {e.message}")
# Action : corriger les paramètres de la requête
429 — RateLimitError
try:
# Trop de requêtes ou quota dépassé
client.responses.create(
model="gpt-5.3",
input="Test"
)
except RateLimitError as e:
print(f"Code : {e.status_code}") # 429
print(f"Message : {e.message}")
# Action : attendre et réessayer avec backoff exponentiel
500/503 — InternalServerError
try:
client.responses.create(
model="gpt-5.3",
input="Test"
)
except InternalServerError as e:
print(f"Code : {e.status_code}") # 500 ou 503
print(f"Message : {e.message}")
# Action : réessayer après un délai, l'erreur est côté OpenAI
Gestionnaire d’erreurs complet
Voici un pattern robuste pour gérer toutes les erreurs possibles :
from openai import OpenAI, APIError, AuthenticationError, RateLimitError
from openai import BadRequestError, APIConnectionError, InternalServerError
import time
client = OpenAI()
def appel_api_robuste(prompt: str, modele: str = "gpt-5.3",
max_retries: int = 3) -> str:
"""Appel API avec gestion complète des erreurs."""
for tentative in range(max_retries):
try:
response = client.responses.create(
model=modele,
input=prompt
)
return response.output_text
except AuthenticationError:
# Ne pas réessayer — la clé est invalide
raise RuntimeError("Clé API invalide. Vérifiez OPENAI_API_KEY.")
except BadRequestError as e:
# Ne pas réessayer — la requête est mal formée
raise RuntimeError(f"Requête invalide : {e.message}")
except RateLimitError:
# Réessayer avec backoff exponentiel
delai = 2 ** tentative
print(f"Rate limit atteint. Attente {delai}s...")
time.sleep(delai)
except InternalServerError:
# Réessayer — erreur côté serveur
delai = 2 ** tentative
print(f"Erreur serveur. Tentative {tentative + 1}/{max_retries}...")
time.sleep(delai)
except APIConnectionError:
# Réessayer — problème réseau
delai = 2 ** tentative
print(f"Erreur connexion. Tentative {tentative + 1}/{max_retries}...")
time.sleep(delai)
raise RuntimeError(f"Échec après {max_retries} tentatives")
# Utilisation
try:
resultat = appel_api_robuste("Bonjour !")
print(resultat)
except RuntimeError as e:
print(f"Erreur fatale : {e}")
Erreurs spécifiques à la Responses API
Contexte trop long
try:
response = client.responses.create(
model="gpt-5.3",
input="x " * 300000 # Dépasse la fenêtre de contexte
)
except BadRequestError as e:
if "context_length_exceeded" in str(e.message):
print("Le prompt est trop long pour ce modèle.")
print("Solutions : tronquer le texte ou utiliser GPT-5.4 (1M tokens)")
Modèle indisponible
try:
response = client.responses.create(
model="gpt-4o", # Modèle retiré !
input="Test"
)
except NotFoundError as e:
print(f"Modèle non trouvé : {e.message}")
print("Utilisez gpt-5.3 ou gpt-5.4 à la place.")
Logging structuré des erreurs
import logging
import json
from datetime import datetime
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("openai_client")
def appel_avec_log(prompt: str) -> str:
"""Appel API avec logging structuré."""
request_id = None
try:
response = client.responses.create(
model="gpt-5.3",
input=prompt
)
logger.info(json.dumps({
"event": "api_success",
"model": response.model,
"tokens": response.usage.total_tokens,
"response_id": response.id,
"timestamp": datetime.now().isoformat()
}))
return response.output_text
except APIError as e:
logger.error(json.dumps({
"event": "api_error",
"status_code": e.status_code,
"message": e.message,
"timestamp": datetime.now().isoformat()
}))
raise
resultat = appel_avec_log("Bonjour !")
Tableau récapitulatif
| Code | Exception | Réessayer ? | Action |
|---|---|---|---|
| 400 | BadRequestError | Non | Corriger la requête |
| 401 | AuthenticationError | Non | Vérifier la clé API |
| 403 | PermissionDeniedError | Non | Vérifier les permissions |
| 404 | NotFoundError | Non | Vérifier le modèle/endpoint |
| 422 | UnprocessableEntityError | Non | Corriger le format |
| 429 | RateLimitError | Oui | Backoff exponentiel |
| 500 | InternalServerError | Oui | Attendre et réessayer |
| 503 | InternalServerError | Oui | Service temporairement indisponible |
Points clés à retenir
- Catégorisez les erreurs : réessayables (429, 500, 503) vs fatales (400, 401, 403)
- Utilisez le backoff exponentiel pour les erreurs réessayables
- Ne réessayez jamais les erreurs d’authentification ou de requête invalide
- Loguez chaque erreur avec contexte (code, message, timestamp)
- Le SDK gère automatiquement 2 retries — configurez
max_retriessi besoin