Errores de API: causas y soluciones
Cada artículo empieza por la respuesta e incluye un comando para que confirmes la causa tú mismo. Los mensajes de error se dejan en inglés, tal como aparecen en tu terminal.
Unexpected token '<' al llamar a una API compatible con OpenAITu cliente recibió HTML donde esperaba JSON. Casi siempre a la base URL le falta /v1 o lo lleva dos veces. Cómo confirmarlo con un solo comando y cómo arreglarlo.401 invalid API key: cuando la clave parece correcta pero sigue fallandoUn 401 con una clave que acabas de copiar suele deberse a espacios en blanco, a la cabecera equivocada o a una clave limitada a modelos a los que no tiene acceso. Cómo saber cuál es tu caso.404 en /v1/chat/completions cuando el endpoint claramente existeRecibir un 404 de un endpoint que sabes que funciona casi siempre es un GET donde la API espera un POST, o una ruta a la que le sobra o le falta un segmento. Cómo distinguirlos.Timeout 524 en peticiones largas a la APIUn 524 viene de una CDN situada delante de la API, no del modelo. Salta cuando el origen no envía nada durante demasiado tiempo, y por eso las peticiones con streaming sobreviven y las demás no.Model not found: cuando el nombre del modelo es casi correctoEste error casi siempre significa que el nombre del modelo no coincide exactamente o que tu clave no tiene acceso a él. Cómo listar lo que realmente puedes llamar.Un 429 de una pasarela de API significa dos cosas distintasUna pasarela devuelve 429 tanto cuando te quedas sin saldo como cuando el upstream está saturado. Uno merece reintentarse y el otro nunca. Cómo distinguirlos por el cuerpo de la respuesta.Error de CORS al llamar a una API de IA desde el navegadorEl error de CORS es el síntoma. El problema real es que una petición desde el navegador entrega tu clave de API a cada visitante. Qué hacer en su lugar y por qué ningún ajuste de cabeceras lo arregla.400 al forzar una llamada a herramienta en un modelo de razonamientoConfigurar tool_choice como any o tool es rechazado por los modelos que siempre razonan antes de responder. Qué enviar en su lugar y qué otros parámetros rechazan esos modelos.Las peticiones mueren exactamente a los 100 segundos detrás de CloudflareUna respuesta larga falla casi exactamente a los 100 segundos con un 524 o un stream cortado. Ese número es un límite del proxy de Cloudflare, no de tu servidor. Cómo confirmarlo y las tres formas de evitarlo.El modelo devuelve una cadena vacía pero igualmente te cobranLa respuesta llega con HTTP 200, content es una cadena vacía y el registro de uso muestra tokens de salida cobrados. En modelos de razonamiento casi siempre es max_tokens agotado antes de producir texto visible.Una respuesta en streaming se detiene a mitad de fraseLlegan tokens, luego dejan de llegar, y no salta ningún error. La diferencia entre un stream completo y uno cortado es una sola línea en el cuerpo SSE, y la mayoría del código cliente nunca la comprueba.Un modelo que ayer funcionaba ahora falla para todos en el mismo grupo de clavesUn modelo que funcionaba empieza a devolver errores para todas las claves de un grupo, mientras los demás grupos no se ven afectados. Es enrutamiento, no el modelo: una sola cuenta upstream defectuosa puede tumbar todo un grupo.La factura es más alta de lo que justifica el recuento de tokensTus totales de tokens parecen modestos, pero el cargo no. En los modelos de la familia Claude la causa habitual es la dirección de la caché: una escritura en caché cuesta más que la entrada normal, una lectura cuesta una fracción, y los mismos tokens pueden diferir doce veces.Claude Code y Codex necesitan base URL distintas en la misma pasarelaLa misma pasarela, la misma clave, dos agentes de programación, y una base URL que funciona en uno falla en el otro. La regla es sencilla cuando sabes qué cliente añade la ruta por su cuenta.405 Method Not Allowed al llamar a una API de IAUn 405 en un endpoint de IA casi nunca significa que el método esté mal. Significa que el POST cayó en un sitio que solo sirve páginas, normalmente el dominio a secas, porque a la base URL le falta /v1. Cómo confirmarlo con un comando.404 en /responses: la Responses API también necesita el prefijo de versiónLos clientes que pasan de chat/completions a la Responses API a menudo pierden el prefijo de versión. El 404 viene del borde de la red, antes de que se ejecute ningún código de la API, así que la llamada nunca aparece en tu registro de uso.context_length_exceeded: qué cuenta realmente para el límiteEl límite cubre toda la conversación más el espacio reservado para la respuesta, no solo tu último mensaje. Por qué recortar el prompt a menudo no ayuda y qué recortar en su lugar.529 overloaded_error de Claude: qué es y qué hacer529 significa que el upstream está saturado en este momento. No es un problema de cuota ni algo que tu clave pueda arreglar. Cómo distinguirlo del 429 y qué patrón de reintentos ayuda de verdad.401 con una clave que es sin duda correcta: revisa el formato de la cabeceraUna clave puede ser perfectamente válida y aun así producir un 401 si la cabecera está mal construida. Las tres formas en que falla y cómo ver la cabecera que tu cliente envió realmente.400 unsupported parameter en un modelo de razonamientoLos modelos de razonamiento rechazan parámetros de muestreo que cualquier otro modelo acepta. Cuáles quitar, por qué el valor por defecto suele ser lo que querías de todos modos y cómo mantener un único camino de código para ambos tipos de modelo.Falta el uso de tokens en una respuesta en streamingUna respuesta en streaming no incluye recuento de tokens a menos que lo pidas. Cómo activarlo, dónde llega el fragmento final y qué hacer cuando una pasarela no lo envía.400 en una llamada a herramienta: cada tool_use necesita su tool_resultEl error aparece un turno después del fallo, y eso es lo que lo hace confuso. La regla de emparejamiento, la regla de orden y cómo reproducirlo a propósito para arreglarlo de una vez.El modo JSON sigue devolviendo texto que no se puede analizarresponse_format restringe la forma, no el final. El truncamiento, la falta de validación del esquema y el texto alrededor del objeto rompen el análisis cada uno de una manera distinta.La llamada funciona en curl pero no desde tu aplicaciónLa misma clave, la misma URL, un resultado distinto. La diferencia casi siempre está en algo que curl no hace: un proxy, una variable de entorno obsoleta, una restricción de IP o una biblioteca que reescribe tu petición.SSL certificate verify failed al llamar a una API de IAUn fallo TLS en tu SDK mientras curl funciona es casi siempre un proxy corporativo o un antivirus que vuelve a firmar el tráfico. Por qué desactivar la verificación es la solución equivocada y cuáles son las tres correctas.socket hang up en mitad de una respuesta en streamingUn stream que se detiene a mitad te deja con una respuesta parcial y sin error del modelo. Cómo distinguir una caída de red de una interrupción en el upstream, y qué hacer en cada caso.Claude Code: API Error 400 prompt is too longEl error menciona la petición, pero la causa es el contexto acumulado de la sesión: archivos leídos, salida de herramientas e historial de la conversación se reenvían en cada turno. Qué limpiar y qué conservar.Imagen de entrada rechazada por un modelo de visiónLos endpoints de visión rechazan imágenes por cuatro motivos distintos que producen errores casi idénticos. Cómo distinguirlos antes de ponerte a recodificar.El prompt de sistema se comporta distinto según el modeloLas dos formas de API dominantes colocan las instrucciones de sistema en sitios distintos. El código escrito para una se degrada en silencio en la otra en lugar de fallar, lo cual es peor que un error.Leer bien un 429: retry-after y las cabeceras de límiteLa mayoría del código de reintentos adivina. La respuesta suele decirte exactamente cuánto esperar y qué límite alcanzaste. Cómo leerla y qué hacer cuando falta la cabecera.Los modelos de un endpoint personalizado no aparecen en la lista del clienteLos clientes de escritorio construyen su lista de modelos de formas distintas, y varios nunca llaman a /v1/models. Cómo saber qué tipo tienes y qué hacer en cada caso.Respuesta vacía con finish_reason content_filterUna respuesta vacía con content_filter como motivo de finalización significa que un sistema de seguridad la detuvo. Cómo distinguirlo del truncamiento y de un fallo real, y lo que te cuesta.Las marcas de tiempo del registro de uso no coinciden con cuándo hiciste la llamadaUna llamada que aparece a horas de distancia de cuando la hiciste es casi siempre una diferencia de zona horaria y no un registro perdido. Cómo alinear ambos antes de reportar un problema de facturación.Cobrado dos veces por lo que parecía una sola peticiónUn timeout en el lado del cliente no detiene el trabajo que ya se está ejecutando en el servidor. La forma habitual de un doble cargo accidental y los dos cambios que lo evitan.