Aller au contenu principal

Erreurs

Chaque échec est un corps JSON accompagné d’un statut HTTP. Voici la réponse à une requête envoyée sans clé :

{
"error": {
"message": "Missing API key. Send it as: Authorization: Bearer <your OceanToken key>.",
"type": "authentication_error",
"param": null,
"code": "invalid_api_key"
}
}

Basez vos branchements sur code. C’est un vocabulaire fixe que nous gardons stable ; message est destiné aux personnes et sa formulation peut changer. type regroupe les codes en familles qui se traitent de la même façon. Le statut HTTP dit la même chose avec moins de précision : les clients existants qui s’appuient dessus continuent de fonctionner.

Codes​

HTTPtypecodeCe qui s’est passéQue faire
400invalid_request_errorinvalid_requestLa requête était mal formée : un champ manquant, une valeur que le modèle n’accepte pas, une image invalide.Corrigez la requête. Ne la renvoyez pas telle quelle.
400not_found_errormodel_not_foundLe nom de model n’existe pas.Choisissez un nom dans GET /v1/models.
400insufficient_creditsinsufficient_creditsVos crédits disponibles sont épuisés. Rien n’a été exécuté ni facturé.Ajoutez des crédits, puis réessayez.
400insufficient_creditskey_budget_exceededLa limite de crédits propre à cette clé est atteinte (votre compte a peut-être encore des crédits).Relevez la limite de la clé, attendez sa réinitialisation ou utilisez une autre clé.
400insufficient_creditsrequest_exceeds_balanceVotre solde est supérieur à 0 $, mais ce qui reste une fois réservée la part de vos requêtes en cours est inférieur au coût maximal possible de cette requête. Ce pire cas correspond à l’entrée au prix d’entrée plein, plus max_tokens de sortie (plafonné à la sortie maximale du modèle ; sans max_tokens, cette limite, au plus 16 384 tokens), multiplié par n, plus tout frais par requête ou de recherche, au prix le plus élevé que pourrait facturer n’importe quel canal du modèle, prix de contexte long et de raisonnement compris. Rien n’a été exécuté ni facturé.Baissez max_tokens ou raccourcissez l’entrée, ou ajoutez des crédits.
400content_policy_violationcontent_filteredUn contrôle de sécurité a refusé la requête avant l’exécution du modèle. Non facturé.Modifiez l’entrée. Réessayer avec la même entrée donne la même réponse.
401authentication_errorinvalid_api_keyPas de clé, une clé inconnue ou une clé supprimée.Vérifiez l’en-tête Authorization: Bearer sk-....
401authentication_errorkey_expiredLa date d’expiration de la clé est passée.Créez une nouvelle clé.
403permission_errormodel_not_allowedLa clé est valide, mais ce modèle ne fait pas partie de ceux autorisés pour votre compte.Utilisez un modèle de GET /v1/models.
403permission_errorforbiddenLa clé ne peut pas effectuer cette opération. La gestion des clés API en fait partie : une clé API ne peut ni créer, ni modifier, ni faire tourner, ni supprimer des clés.Gérez les clés dans la console ; sinon, utilisez une clé ayant la bonne portée.
404not_found_errornot_foundChemin inconnu, ou un id de vidéo / de tâche qui n’existe pas.Vérifiez l’URL et l’id.
409idempotency_erroridempotency_key_reusedL’Idempotency-Key a déjà été utilisée avec un corps différent.Utilisez une nouvelle clé pour une nouvelle requête. Voir Nouvelles tentatives.
409idempotency_erroridempotency_key_in_progressLa première requête avec cette clé est toujours en cours.Attendez Retry-After secondes, puis renvoyez la même requête.
429rate_limit_errorrate_limitedVous avez dépassé la limite de requêtes ou de tokens par minute de votre clé.Patientez jusqu’à Retry-After ; voir Limites.
429rate_limit_errorprovider_overloadedTous les canaux du modèle sont saturés en ce moment. Voir Nouvelles tentatives et basculement.Réessayez avec un délai croissant, ou changez de modèle.
501invalid_request_errornot_supportedCet endpoint n’est pas proposé : lots (/v1/batches), fine-tuning (/v1/fine_tuning), et lister, lire ou supprimer des fichiers sous /v1/files.Ne réessayez pas. Envoyez plutôt chaque requête à son endpoint habituel.
503api_errortemporarily_unavailableLa passerelle n’a pas pu vérifier à l’instant ce dont elle a besoin pour accepter la requête, comme le solde de votre organisation. Rien n’a été exécuté ni facturé.Réessayez après Retry-After secondes.
5xxapi_errorprovider_errorLe modèle a échoué, après les nouvelles tentatives et le basculement de la passerelle. Non facturé.Réessayez avec un délai croissant ; si cela persiste, changez de modèle.
408api_errortimeoutUn stream n’a rien reçu du modèle pendant 120 secondes après son démarrage.Réessayez avec un délai croissant.
504api_errortimeoutLa requête a dépassé la fenêtre de 240 secondes.Passez la réponse en streaming, raccourcissez la requête ou utilisez un endpoint asynchrone.

Tout ce qui ne figure pas dans ce tableau est une api_error. De nouveaux codes peuvent être ajoutés ; les codes existants ne sont ni renommés ni supprimés.

L’ID de requête​

Les réponses aux requêtes de modèle portent l’en-tête x-oceantoken-request-id. Enregistrez-le avec vos erreurs et citez-le quand vous nous écrivez. Une requête refusée à cause de sa clé (401) n’a jamais atteint de modèle et n’en a pas.

Une réponse réussie a aussi un id dans son corps, et chaque fragment d’un stream porte le même id. C’est le Request ID que la console affiche sous Logs, avec le statut, la latence et le coût de la requête, et l’id que recherche GET /v1/usage/{request_id}.

Nouvelles tentatives​

Avant qu’une erreur ne vous parvienne, la passerelle a déjà réessayé et, si le modèle a un autre canal, y a déplacé la requête. Nouvelles tentatives et basculement explique ce qu’elle gère et ce qu’elle vous laisse.

Réessayez uniquement dans ces cas : 429 ; tout 5xx sauf 501 ; une erreur timeout ; une panne réseau (connexion coupée, délai dépassé côté client). Tout ce qui est dans la plage 400, et 501 not_supported, échouera de la même façon tant que la requête ou le compte n’auront pas changé.

Utilisez un délai exponentiel avec une part aléatoire, en commençant vers une seconde et en plafonnant vers trente ; quand la réponse contient Retry-After (un nombre de secondes), attendez au moins ce temps-là. Retry-After n’est garanti que sur 409 idempotency_key_in_progress ; sur un 429 ou un 503, il peut manquer : utilisez alors votre propre délai.

# Retry only what can succeed on a second try: 429, 408 (timeout), every 5xx
# except 501 (an endpoint that is not offered) and network failures,
# with exponential backoff and jitter, honouring Retry-After when it is sent.
import os
import random
import time

from openai import APIConnectionError, APIStatusError, OpenAI

client = OpenAI(
base_url=os.getenv("OCEANTOKEN_BASE_URL", "https://api.oceantoken.ai/v1"),
api_key=os.environ["OCEANTOKEN_API_KEY"],
max_retries=0, # the loop below does the retrying
)


def with_retries(call, attempts=5):
for attempt in range(attempts):
try:
return call()
except APIConnectionError:
if attempt == attempts - 1:
raise
delay = None # network failure: back off and try again
except APIStatusError as e:
retryable = e.status_code in (408, 429) or (e.status_code >= 500 and e.status_code != 501)
if not retryable or attempt == attempts - 1:
raise
retry_after = e.response.headers.get("retry-after")
delay = float(retry_after) if retry_after else None
time.sleep(delay if delay is not None else min(30, 2**attempt) + random.random())


models = with_retries(lambda: client.models.list())
print(len(models.data), "models")

Réessayer une requête payante​

Les requêtes d’images, de vidéo et de synthèse vocale sont facturées à l’exécution. Une nouvelle tentative après un délai réseau dépassé les exécuterait sinon une seconde fois. Envoyez un en-tête Idempotency-Key (n’importe quelle chaîne unique, jusqu’à 255 caractères, par exemple un UUID) sur POST /v1/images/generations, /v1/images/edits, /v1/videos et /v1/audio/speech :

  • La première requête s’exécute normalement et sa réponse est conservée 24 heures.
  • Une nouvelle tentative avec la même clé et le même corps récupère cette réponse, marquée de l’en-tête Idempotency-Replayed: true. Rien n’est exécuté ni facturé.
  • La même clé avec un corps différent est refusée avec 409 idempotency_key_reused.
  • Une nouvelle tentative alors que la première requête est toujours en cours reçoit 409 idempotency_key_in_progress avec Retry-After.
  • Une réponse 5xx n’est pas conservée : une nouvelle tentative après une panne du fournisseur s’exécute à nouveau.

Les clés sont limitées à votre clé API. L’en-tête est ignoré sur tous les autres endpoints, et sur ceux ci-dessus une requête sans lui se comporte exactement comme avant. Les réponses de plus de 8 Mo ne sont pas conservées ; la requête s’exécute quand même, seule la relecture ne s’applique pas.

Erreurs en streaming​

Avec "stream": true, une erreur survenue avant le premier token est une réponse d’erreur JSON ordinaire avec le statut ci-dessus. Une erreur survenue après le début du stream arrive sous la forme d’un dernier fragment data: dont le contenu est le même objet error, puis le stream se termine.

Un stream qui se termine trop tôt, parce que la connexion a été coupée, que vous vous êtes déconnecté ou qu’une erreur l’a interrompu, est facturé aux prix habituels du modèle pour :

  • son prompt, en entier ;
  • la sortie streamée jusque-là. Le raisonnement streamé par un modèle de raisonnement compte comme sortie, même si aucun texte de réponse n’était encore arrivé.

La sortie que le modèle a pu continuer à générer après l’arrêt du stream n’est pas facturée. Un stream terminé avant de produire la moindre sortie n’est pas facturé du tout.

Solde épuisé​

Quand votre solde est inférieur ou égal à 0 $, toute requête vers un modèle payant est refusée avec 400 insufficient_credits. Rien n’est exécuté ni facturé. Ajoutez des crédits et réessayez. Les modèles dont l’ID se termine par :free fonctionnent toujours avec un solde de 0 $.

Quand votre solde est supérieur à 0 $ mais inférieur au coût maximal possible d’une requête, seule cette requête est refusée avec 400 request_exceeds_balance ; les requêtes plus petites passent toujours. Le message indique ce que la requête pourrait coûter et quel est votre solde. Baissez max_tokens ou raccourcissez l’entrée pour l’exécuter dans les limites de votre solde, ou ajoutez des crédits.

Migrer depuis OpenAI​

Les corps d’erreur ont le même objet error que ceux d’OpenAI. Deux cas répondent avec un statut ou un code différent :

CasOpenAIOceanToken
Solde épuisé429 insufficient_quota400 insufficient_credits
Modèle inconnu404 model_not_found400 model_not_found

Les valeurs de code sont toutes les nôtres ; Codes les liste. Quelques statuts ont un sens qui nous est propre : un modèle saturé renvoie 429 provider_overloaded (OpenAI répond 503), 408 timeout est un stream resté muet, 409 est un conflit d’idempotence, et 501 not_supported est un endpoint que nous ne proposons pas. Si votre code lit 429 insufficient_quota comme un manque d’argent, cherchez plutôt 400 insufficient_credits ; ce n’est pas un 429, donc une boucle de nouvelles tentatives ne tourne pas dessus. Un modèle inconnu est un 400 : un gestionnaire qui attend un 404 ne le voit pas ; basez-vous sur code et la vérification fonctionne dans les deux cas.

Politique de contenu​

Les requêtes qui déclenchent un contrôle de sécurité sont refusées avec 400 content_filtered. Le contrôle a lieu avant l’appel au modèle : la requête n’est donc pas facturée.

Retrouver une requête échouée​

Chaque échec est enregistré dans la console sous Logs, avec son statut et le corps de la réponse. Retrouvez-le par son heure et son modèle, et citez son x-oceantoken-request-id quand vous nous écrivez.