La estructura de un error
Los errores llegan como JSON con un objeto error. La mayoría responde con la estructura de la plataforma; audio, imágenes, decisiones y algunos errores de inferencia responden con la de OpenAI. Ambas traen un code: basa tu lógica en él, nunca en el mensaje.
{
"error": {
"code": "model-not-found",
"category": "client",
"message": "no active deployment serves this model for the operation",
"request_id": "01K7YQ4D8M2P6S9V3X5Z7B1C4F"
}
}Códigos de estado
| Estado | Códigos de error típicos | Qué hacer |
|---|---|---|
| 400 | invalid-request | Corrige la solicitud; no la reintentes sin cambios. |
| 401 | api-key-invalid, api-key-unknown, api-key-revoked | Revisa la API key y la región. Consulta Autenticación. |
| 402 | payment-required, credits-exhausted | Suscríbete, o recarga los créditos de los modelos adicionales. |
| 403 | policy-denied, team-not-selectable | Al propietario de la API key le falta el permiso, o debes enviar X-Team-Id. |
| 404 | model-not-found | El modelo no sirve este endpoint, o no es tuyo: revisa GET /v1/models. |
| 413 | request-body-too-large | Cuerpos JSON de hasta 8 MiB, cargas de audio de hasta 25 MiB. |
| 429 | rate-limit-exceeded, *-concurrency-exceeded, provider-rate-limited | Reintenta con backoff, o envía menos solicitudes a la vez. |
| 500 | internal-error | Reintenta una vez; si persiste, contacta a soporte con el ID de solicitud. |
| 502 | forwarder-failed | El modelo respondió algo inválido. Reintenta con backoff. |
| 503 | provider-unavailable | Por ahora no hay ningún modelo disponible. Reintenta con backoff. |
| 503 | model-not-priced | El modelo adicional todavía no tiene precio. No reintentes; contacta a soporte. |
| 504 | provider-timeout | El modelo no respondió a tiempo. Reintenta, o acorta la solicitud. |
Reintentos con backoff
Reintenta solo 429, 503 provider-unavailable y 504, esperando más tiempo cada vez. Los clientes oficiales de OpenAI ya reintentan dos veces por su cuenta (max_retries); esta es una política más larga, pensada para trabajos por lotes:
import random
import time
from openai import APIStatusError, OpenAI
RETRYABLE = {429, 503, 504}
def create_with_retries(client: OpenAI, attempts: int = 5, **request):
"""Retries only what can succeed later: limits, an unavailable or slow model."""
for attempt in range(attempts):
try:
return client.chat.completions.create(**request)
except APIStatusError as error:
if error.status_code not in RETRYABLE or attempt == attempts - 1:
raise
time.sleep(min(30, 2**attempt) + random.random()) # exponential backoff with jitterID de solicitud
Cada respuesta trae un header X-Request-ID. Envía el tuyo (un ULID) para vincular una solicitud con tus logs, o lee el que generó la plataforma. Cítalo cuando contactes a soporte y úsalo para encontrar la solicitud en el registro de solicitudes.
curl -i "$CCSIO_BASE_URL/chat/completions" \
-H "Authorization: Bearer $CCSIO_API_KEY" \
-H "X-Request-ID: 01K7YQ4D8M2P6S9V3X5Z7B1C4F" \
-H "X-Session-Id: support-ticket-4312" \
-H "Content-Type: application/json" \
-d '{"model": "qwen3.8-flash-next", "messages": [{"role": "user", "content": "Hi"}]}'
# HTTP/2 200
# x-request-id: 01K7YQ4D8M2P6S9V3X5Z7B1C4F