Router — Codes d'erreur
Router suit les conventions HTTP standard. Le corps de réponse est toujours un objet JSON {"error": {"message": "...", "type": "..."}} — facile à parser.
Tableau des codes
| Code | Type | Retry ? |
|---|---|---|
| 200 | Succès | — |
| 400 | configuration_error |
Non |
| 400 | invalid_response_format / retention_not_supported |
Non |
| 402 | billing_error |
Non |
| 403 | permission_error |
Non |
| 412 | guard_halt |
Non |
| 422 | idempotency_conflict |
Non |
| 422 | schema_validation_failed |
Non (corrigez le prompt ou le schéma) |
| 429 | rate_limit_error |
Oui — backoff exponentiel |
| 500 | internal_error |
Oui (3 tentatives) |
| 502 | provider_error |
Oui après 30s |
Détails par code ci-dessous.
400 — Configuration error
{
"error": {
"message": "Unknown model: anthropic/claude-foo",
"type": "configuration_error"
}
}
Causes fréquentes :
- Identifiant de modèle inexistant (typo, modèle déprécié)
- Body JSON invalide ou champ requis manquant (
messages) temperaturehors plage [0, 2]max_tokensau-delà du contexte du modèle
Action : corrigez la requête et renvoyez. Pas de retry automatique utile.
invalid_response_format (400, param: "response_format")
response_format n'a pas une forme utilisable : type inconnu, ou type: "json_schema" sans json_schema.name / json_schema.schema. Formes acceptées : {"type": "text"}, {"type": "json_object"}, {"type": "json_schema", "json_schema": {"name": ..., "schema": {...}}}.
retention_not_supported (400, param: "no_retention")
Vous avez demandé no_retention: true (ou X-No-Retention: true) sur un modèle qui ne peut pas garantir l'absence de rétention/entraînement. Router refuse plutôt que de servir une garantie affaiblie. Action : choisissez un autre modèle, ou retirez no_retention (voir Router — Confidentialité et rétention).
402 — Insufficient credits
{
"error": {
"message": "Insufficient credits",
"type": "billing_error"
}
}
Votre balance Router est en-dessous du coût estimé de la requête.
Action :
- Rechargez via
/api/v1/billing/balance(ou l'interface) - Activez l'auto-recharge pour éviter le problème (voir Router — Facturation)
- Côté code client : capture explicite + notification utilisateur (« Crédits IA épuisés, contactez votre administrateur »)
Pas de retry automatique — la requête échouera systématiquement tant que la balance n'est pas reconstituée.
403 — AI not enabled
{
"error": {
"message": "AI not enabled",
"type": "permission_error"
}
}
L'organisation propriétaire de cette clé API n'a pas le module IA activé.
Action : un administrateur doit activer le module dans Paramètres → Organisation → Modules → IA. Aucun retry n'aidera tant que ce n'est pas fait.
412 — Guard halt
{
"error": {
"message": "Guard blocked this request — 2 sensitive detection(s) in strict-mode policy",
"type": "guard_halt",
"audit_id": "halt-uuid-abc",
"detections": [
{"detector": "regex:nas", "category": "pii", "severity": "critical",
"position_start": 23, "position_end": 34}
]
}
}
Votre politique Guard est en mode strict et la requête contient au moins une détection critical ou high. L'appel upstream n'a pas eu lieu — aucun token consommé, aucun coût facturé.
Actions :
- Modifier le contenu de la requête pour retirer la donnée sensible
- OU désactiver le mode strict sur votre politique dans
/settings/guard - OU ajouter un allowlist pattern qui couvre le contenu légitime
- Utiliser l'
audit_idpour inspecter la décision détaillée via Router — API d'audit
Le guard.halt webhook est déclenché en parallèle — voir Router — Webhooks pour brancher un alerting temps réel.
422 — Idempotency conflict
{
"error": {
"message": "Idempotency-Key already used with a different request body. Use a new key.",
"type": "idempotency_conflict"
}
}
Vous avez envoyé la même Idempotency-Key avec un body différent. Router refuse pour éviter qu'une réutilisation accidentelle de clé ne corrompe votre cache.
Actions :
- Si c'est un vrai retry, envoyez le même body avec la même clé
- Si c'est une nouvelle requête, générez une nouvelle clé (UUID recommandé)
422 — Schema validation failed
{
"error": {
"message": "Model output did not satisfy response_format.json_schema: $.ville: missing required properties: ville",
"type": "invalid_request_error",
"code": "schema_validation_failed",
"param": "response_format",
"raw_preview": "{\"nom\": \"Alice\"}..."
}
}
Sur un modèle sans support natif de json_schema, la sortie ne respecte pas le schéma demandé (ou n'est pas du JSON). Router ne corrige jamais silencieusement : la réservation de crédits est libérée (aucune facturation pour cette sortie) et le brut est annexé en raw_preview (tronqué à 2000 caractères).
Actions :
- Renforcer le prompt (répéter les champs requis, exiger « JSON uniquement »)
- Simplifier le schéma (moins de champs requis,
additionalProperties: falseexplicite) - Basculer sur un modèle à support natif (
GET /api/v1/models→supported_parameters)
429 — Rate limited
{
"error": {
"message": "Rate limited",
"type": "rate_limit_error"
}
}
L'organisation a dépassé sa limite de débit (par défaut : 60 requêtes/minute, ajustable par contrat).
Stratégie de retry recommandée : exponential backoff avec jitter.
import time
import random
def call_with_retry(client, **kwargs):
delays = [1, 2, 4, 8, 16] # secondes
for attempt, base_delay in enumerate(delays):
try:
return client.chat.completions.create(**kwargs)
except RateLimitError:
if attempt == len(delays) - 1:
raise
jitter = random.uniform(0, base_delay * 0.5)
time.sleep(base_delay + jitter)
À noter : Router lit l'en-tête
Retry-Afterenvoyé par les fournisseurs en amont. Quand disponible, il est forwardé dans la réponse — utilisez-le si présent au lieu d'un backoff fixe.
500 — Internal error
{
"error": {
"message": "...",
"type": "internal_error"
}
}
Erreur inattendue côté Router (DB, timeout, exception non gérée). Toujours loggé côté serveur.
Action : retry avec backoff (3 tentatives max). Si l'erreur persiste après les 3, signalez à [email protected] avec le request_id de la réponse (en-tête x-request-id).
502 — Provider error
{
"error": {
"message": "Provider error",
"type": "provider_error",
"details": "Anthropic returned 503 service_unavailable"
}
}
Tous les fournisseurs IA compatibles avec votre requête ont échoué en cascade (Router a déjà essayé le fallback automatique). C'est rare — généralement causé par une panne globale d'Anthropic + OpenAI simultanément, ou par une panne réseau côté Meridian.
Action :
- Vérifier l'état des services
- Attendre 30 secondes puis retry une fois
- Si toujours 502 : signaler à support, utiliser un cache local en attendant
Bonnes pratiques générales
Idempotency
Pour les workloads où le même résultat doit être renvoyé sur un retry (ex. génération d'un document à partir d'un input fixe), envoyez un en-tête Idempotency-Key :
curl https://router.signalorange.ca/api/v1/chat/completions \
-H "Authorization: Bearer $ROUTER_API_KEY" \
-H "Idempotency-Key: req_2026-04-20-doc-123" \
...
⚠️ En cours d'implémentation — pour l'instant, gérez l'idempotence côté client avec un cache de réponses indexé sur le hash de la requête.
Logging des erreurs
Loggez systématiquement, pour chaque erreur :
- Code HTTP
error.typeeterror.message- En-tête
x-request-id(utile pour le support) - Timestamp local
- Modèle demandé vs modèle réellement appelé (champ
"model"de la dernière réponse réussie)
Circuit breaker
Pour les apps à haut volume, considérez un circuit breaker côté client : si Router renvoie 5 erreurs 5xx d'affilée, ouvrez le circuit pendant 60 secondes pour éviter d'aggraver la charge en aval.