Errores y límites
Códigos de error de GetVibe API: 401 (clave), 402 (saldo), 403 (IP), 429 (límite de solicitudes). Cómo gestionar errores y reintentar con retroceso exponencial.
Los errores producidos por GetVibe en /v1/* tienen una envoltura JSON con error.message, error.type y error.code. No dependas del texto del mensaje ni de los encabezados del servicio de terceros como contrato.
Formato de error
{
"error": {
"message": "insufficient balance",
"type": "insufficient_quota",
"code": 402,
"request_id": "8d4b6b3a-..."
}
}Códigos de respuesta
| Parámetro | Tipo | Descripción |
|---|---|---|
401 | authentication_error / 401 | Falta la clave, tiene un formato incorrecto o está deshabilitada. No vuelvas a intentarlo hasta corregir las credenciales. |
402 | insufficient_quota / 402 | No hay saldo ni límite disponible; esperar no lo solucionará. Un 402 nunca incluye Retry-After y no debe reintentarse: añade fondos o espera a que se restablezca la ventana de suscripción. |
403 | permission_error or policy type / 403 | La IP, el modelo o la política no permite la solicitud. No vuelvas a intentarlo sin cambiar la solicitud o la configuración. |
429 | rate_limit_exceeded, inflight_client_cap or rate_limit_error / 429 | Tu límite de solicitudes, tu límite de concurrencia, una reserva de saldo retenida brevemente por tus propias solicitudes simultáneas (causa reserved_in_flight) o un límite del proveedor. Reintenta solo después de Retry-After; un 429 nunca significa que tu saldo se haya agotado. |
410 | media_endpoint_retired / media_endpoint_retired | Solo /v1/images/edits, /v1/video/generations y /v1/videos (retirados). No vuelvas a intentarlo; cambia a /api/media/generate. /v1/images/generations sí se ofrece. |
413 | invalid_request_error / 413 | Solo Files API: el archivo supera los 50 MiB. Reduce el archivo y crea una solicitud nueva. |
503 | overloaded / 503 | Sobrecarga global del edge. Vuelve a intentarlo después de Retry-After: 2. Otros errores 503 pueden no admitir reintentos sin cambiar el modelo o la solicitud. |
Errores de solicitud (400, 413, 422): códigos y soluciones
Cada error de solicitud incluye un error.code estable de la tabla siguiente, error.param con el campo al que corresponde (null cuando el modelo no indicó ninguno) y un enlace a la fila correspondiente al final de error.message; Codex y otras CLI solo muestran el mensaje, por lo que el enlace también aparece allí.
| error.code | error.param | Qué hacer |
|---|---|---|
unsupported_parameter | nombre del campo | El modelo o canal seleccionado no acepta este parámetro. Elimínalo de la solicitud (en Codex/IDE, de la configuración) y vuelve a intentarlo. |
invalid_parameter_value | nombre del campo | El parámetro está presente, pero su valor no está permitido para este modelo: por ejemplo, un valor de temperature distinto de 1 con reasoning activado, max_tokens por encima del máximo o effort "none" cuando no se puede desactivar reasoning. Corrige el valor como se indica en el mensaje. |
missing_parameter | nombre del campo | Falta un campo obligatorio o está vacío. Añádelo. |
invalid_tool_schema | tools[].function.* | Se rechazó una definición de herramienta: los nombres solo pueden usar letras latinas, dígitos, "_" y "-"; los parámetros deben ser un esquema JSON cuyo tipo raíz sea "object". También puedes elegir otra variante del modelo. |
tool_choice_unsupported | tool_choice | El modelo no admite una elección de herramienta forzada. Envía tool_choice "auto" o "none". |
invalid_tool_history | messages / input | El historial contiene una llamada a una herramienta sin resultado. Añade el resultado con el mismo id o elimina la llamada junto con su resultado al recortar el historial. |
invalid_image | — | No se pudo leer la imagen. Envía un archivo PNG, JPEG, WebP o GIF completo (no se aceptan BMP, TIFF, AVIF ni SVG). |
unsupported_input_modality | — | El modelo no acepta este tipo de archivo adjunto (PDF, audio, video, imágenes). Elimínalo o elige un modelo cuya entrada del catálogo incluya ese tipo de archivo. |
conversation_state_unreadable | — | El razonamiento del historial fue creado por otro canal. La solicitud es válida; reinténtala y, si el error se repite, inicia una conversación nueva. |
invalid_json | — | El cuerpo de la solicitud no es JSON o llegó truncado. Para conversaciones muy largas con imágenes, inicia una conversación nueva o compacta el historial. |
request_too_large | — | La solicitud es demasiado grande. Reduce los archivos adjuntos o el historial. |
request_rejected_by_channel | — | El canal del modelo rechazó la solicitud sin indicar el motivo; lo más probable es que la solicitud sea válida. Reinténtala; si el rechazo se repite, elige otra variante del modelo (el sufijo después de los dos puntos) o el modelo sin sufijo. Si esto no ayuda, contacta con soporte e incluye el request_id. |
model_not_available_on_route | — | La ruta no está configurada para este modelo. Elige otro modelo o variante. |
context_length_exceeded | messages / input / prompt | La solicitud no cabe en la ventana de contexto. Compacta el historial (en Codex: /compact) o elige un modelo con una ventana más grande. |
content_moderation | — | El filtro de contenido del proveedor bloqueó la solicitud o la respuesta. Reformúlala o elige otro modelo. |
invalid_request | — | No se reconoció la causa. Comprueba la solicitud con la referencia de la API; si es correcta, contacta con soporte e incluye el request_id de la respuesta. |
Encabezados de respuesta
| Parámetro | Tipo | Descripción |
|---|---|---|
x-pv-cost-rub | string | Estimación aproximada del costo en rublos. En los streams, x-pv-cost-rub está disponible cuando se conoce la estimación de entrada; pv_cost_rub en el evento de uso final requiere x-pv-cost: 1. El historial de uso contiene el débito real. |
x-pv-generation-id | string | Id. del registro del historial de uso (GET /v1/generations/{id}). Solo se devuelve para solicitudes de chat/completions sin streaming. |
x-pv-dropped-params | string | Parámetros de solicitud separados por comas que la ruta seleccionada no acepta y que, por lo tanto, no se enviaron al modelo (por ejemplo, temperature,top_p). Solo aparece cuando realmente se omitió algo, tanto en las respuestas como en los errores. Nunca descartamos un parámetro silenciosamente: si no hay header, todo lo que enviaste llegó al modelo sin cambios. |
Retry-After | integer | Segundos de espera. El edge lo establece para la limitación de velocidad 429, la concurrencia 429 (5), la sobrecarga global 503 (2) y algunos 402 transitorios. No se presupone para todos los 429/503. |
Errores antes y después de que comience la respuesta
Una transmisión lenta (stream: true) recibe 200 y : pv-keepalive comentarios después de 5 segundos de silencio para que la conexión no parezca inactiva; una solicitud larga sin transmisión recibe 200 y espacios en blanco después de su primer token. A partir de ese momento, el estado no puede cambiar y llega un error en el cuerpo. Si tu cliente recurre a otro proveedor ante un error HTTP, envía x-pv-honest-errors: 1 (o solicita al soporte que lo habilite para la cuenta): en ese caso no hay keepalive ni un 200 anticipado antes del primer byte de respuesta, y cada fallo es un estado HTTP normal con un cuerpo JSON. El costo es un socket silencioso hasta el primer token; el tiempo de espera de los encabezados debe cubrirlo.
Un error después de que comenzó la respuesta es un evento terminal: para chat event: error con {"error":{message,type,code,status},"choices":[{"finish_reason":"error"}]} seguido de data: [DONE]; para /v1/responses event: response.failed que lleva el mismo error; para /v1/messages, el event: error de Anthropic. code es la causa para la máquina y status es el estado HTTP que habría tenido el error antes de que comenzara la respuesta.
stream: true), no se devuelve x-pv-generation-id porque la facturación termina después de que finaliza el stream. Revisa el historial de solicitudes mediante GET /v1/generations.Límites de frecuencia y concurrencia
Ambos límites dependen del saldo actual de la cuenta y se aplican al conjunto de todas sus claves de API. El nivel se recalcula automáticamente: recarga el saldo y el límite sube; si el saldo cae por debajo de un umbral, el nivel baja. No hay límite de tokens por minuto (TPM).
| Saldo a partir de | Solicitudes por minuto (RPM) | Solicitudes simultáneas |
|---|---|---|
| 0 $ | 300 | 10 |
| 1 $ | 1 100 | 50 |
| 2 $ | 6 600 | 300 |
| 4 $ | 19 800 | 900 |
| 12 $ | 44 000 | 2 000 |
| Parámetro | Tipo | Descripción |
|---|---|---|
429 rate_limit_exceeded | RPM | La cuenta ha enviado tantas solicitudes en los últimos 60 segundos (una ventana deslizante) como permite su nivel. Retry-After es el número de segundos hasta que se libera un cupo en la ventana (al menos 1); x-ratelimit-limit-requests indica tus RPM actuales. Cuerpo: error.cause = key_rate_limited, error.details = { enforced_by: "getvibe", limit, unit: "requests_per_minute", retry_after_seconds }. |
429 inflight_client_cap | concurrency | Ya hay tantas solicitudes en curso como permite el nivel. Una solicitud ocupa su cupo hasta que finaliza; una transmisión lo ocupa hasta su último evento. Retry-After: 5. Cuerpo: error.cause = account_concurrency_limited, error.details = { enforced_by: "getvibe", limit, unit: "parallel_requests", retry_after_seconds: 5 }. |
Personal limit | RPM | Si la cuenta tiene un límite de solicitudes personalizado, este solo puede reducir los RPM del nivel, nunca aumentarlos. |
503 overloaded | service | No es tu límite, sino una medida de protección del servicio: Retry-After: 2 corresponde al límite global para todas las cuentas; Retry-After: 1 indica que un servidor está ocupado. Vuelve a intentarlo después de la pausa. |
429 from a provider | upstream | error.cause = supplier_rate_limited significa que el proveedor del modelo ha limitado la solicitud y que tu propio límite no se ha agotado; channel_rate_limited es el límite compartido de un canal del proveedor (Retry-After: 10, no se ha enviado nada). |
Reintento de solicitudes
Para una respuesta que se puede reintentar, usa primero Retry-After, si está presente. Sin el encabezado, no trates ningún 429 o 503 como reintentable automáticamente: comprueba el estado HTTP y el error.type público, corrige la causa no reintentable y usa un retroceso limitado solo para un error transitorio.
import time, requests
def call_with_retry(url, headers, payload, max_retries=5):
for attempt in range(max_retries):
r = requests.post(url, headers=headers, json=payload)
if r.status_code == 429:
# honor Retry-After, otherwise exponential backoff
wait = int(r.headers.get("Retry-After", 2 ** attempt))
time.sleep(wait)
continue
return r
return r