Los fallos de una API OCR se dividen en tres grupos: solicitudes que ni siquiera se aceptan (401, 413, 415), solicitudes limitadas o agotadas por timeout (429, 5xx) y solicitudes que se completan pero cuyo resultado no sirve (texto vacío, caracteres corruptos o baja confianza). Los dos primeros se localizan con el código de estado; el tercero es el que más veces se confunde con "la interfaz está rota".

Este artículo propone un orden de diagnóstico por síntoma, métodos de preprocesamiento de imágenes, estrategias de reintento y campos de registro, y termina con un bloque de código reutilizable para el manejo de errores.

Nota: las interfaces OCR, los códigos de error y las reglas de límite varían mucho entre proveedores. Este artículo usa como ejemplo el comportamiento habitual en octubre de 2026; la referencia final es la documentación del proveedor y la respuesta real. OpenAI, Google, Microsoft, Alibaba Cloud, Tencent Cloud, Baidu AI Cloud, Tesseract y PaddleOCR son marcas o nombres de producto de sus respectivos titulares; aquí solo se usan para una explicación técnica.

1. Conserva primero cuatro pruebas

Antes de diagnosticar, no te apresures a reintentar: guarda esta información:

  • El código de estado HTTP y los campos error.code y error.message del cuerpo de la respuesta.
  • El identificador de solicitud o x-request-id de las cabeceras.
  • El formato original de la imagen, el tamaño del archivo, las dimensiones en píxeles y la orientación EXIF.
  • La hora de la llamada, la dirección de la interfaz y el nombre del modelo.
Código de estado Significado habitual Qué revisar primero
400 Parámetros o contenido de imagen no válidos Base64, URL, nombres de campo, imagen dañada
401 Fallo de autenticación Clave ausente, caducada o con espacios
403 Sin permiso o cuota restringida Permisos del modelo, estado del proyecto, saldo
413 Cuerpo o archivo demasiado grande Tamaño del archivo, dimensiones, páginas del PDF
415 Tipo de medio no compatible Content-Type, extensión, codificación real
429 Límite de velocidad o concurrencia excedida QPS, concurrencia, Retry-After
500/502/503/504 Fallo del proveedor o timeout Reintento, degradación, página de estado

2. 401 y 403: primero la identidad, después los permisos

Un 401 significa que el servidor no reconoce la clave. Las causas más frecuentes son: falta la cabecera Authorization: Bearer, la clave se copió con espacios o saltos de línea, la variable de entorno está vacía, la clave se rotó, o se envió una clave de la plataforma A a la dirección de la plataforma B.

Para diagnosticar, valida primero con una solicitud mínima y no adivines dentro de la cadena completa del negocio. Confirma el valor que realmente se envía en la cabecera, no solo lo que dice el archivo de configuración. Un 403 suele indicar que la clave es válida pero no tiene permiso para ese modelo o interfaz, o que la cuenta alcanzó un límite o el proyecto está suspendido.

Ten en cuenta además que las claves de una puerta de enlace y las de la dirección nativa del proveedor normalmente no son intercambiables. Al cambiar de dirección, revisa juntos la clave, el nombre del modelo y la ruta de la solicitud.

3. 413 y 415: archivo demasiado grande o formato incorrecto

Un 413 no significa "no se puede reconocer el contenido", sino que la solicitud se rechazó en la capa de transporte. Condiciones habituales:

  • Una imagen supera el límite de tamaño de la interfaz.
  • Las dimensiones son demasiado grandes y la memoria se desborda al decodificar.
  • El PDF tiene demasiadas páginas o se subieron varias a la vez.
  • La codificación Base64 aumenta el tamaño alrededor de un tercio y hace que un archivo que estaba justo en el límite lo supere.

El 415 suele estar relacionado con el formato: la interfaz solo acepta JPG o PNG y se envió HEIC, TIFF o BMP; la extensión es JPG pero el contenido real es WebP; o el Content-Type se escribió como application/json cuando la interfaz espera multipart/form-data.

El preprocesamiento de imágenes debería seguir este orden:

  1. Lee la imagen con una librería y confirma el formato real; no confíes en la extensión.
  2. Escala de forma proporcional según el lado mayor, por ejemplo hasta 2000–3000 píxeles, y vuelve a probar.
  3. Corrige la orientación EXIF para evitar que el texto quede girado y el reconocimiento devuelva vacío.
  4. Convierte al formato admitido y controla la calidad de compresión sin volver ilegibles las letras.
  5. Divide los PDF de varias páginas y procesa página por página, o usa una interfaz que admita el documento completo.
  6. Registra tamaño y dimensiones antes y después del procesamiento para saber en qué paso se superó el límite.

No comprimas una imagen hasta que no se lea solo para pasar un 413. Si los trazos se pegan, la interfaz devolverá éxito con una calidad pésima.

4. 429: límites de velocidad, concurrencia y ritmo de reintento

Un 429 significa, en esencia, "llegaron demasiadas solicitudes o demasiado rápido". Los límites habituales son solicitudes por segundo, por minuto, concurrencia y cuota por tokens o por páginas. Aunque el total no supere la cuota, un pico instantáneo de concurrencia puede activar la limitación.

Principios de manejo:

  • Lee Retry-After y, si existe, espera lo que indique.
  • Si no existe, aplica retroceso exponencial con jitter aleatorio para que todos los clientes no reintenten a la vez.
  • Reintenta solo 429 y 5xx; reintentar 401, 413 o 415 no tiene sentido.
  • Define un número máximo de reintentos y un timeout total para evitar el acumulamiento de tareas.
  • Lleva los picos de tráfico a una cola y envíalos de forma suave según la capacidad del servidor.

Reintentar más no siempre es mejor. En interfaces que cobran por llamada, la facturación de solicitudes fallidas depende de las reglas del proveedor; reintentar a ciegas puede ampliar el costo.

5. Timeouts y 5xx: distingue red de proveedor

En los timeouts, separa el timeout de conexión del de lectura. El de conexión suele indicar un problema de red, DNS, proxy o firewall; el de lectura indica que la solicitud llegó pero el procesamiento tarda demasiado, algo habitual con imágenes grandes, PDF de varias páginas o colas del proveedor.

Conviene definir un timeout específico para las solicitudes OCR y no reutilizar el timeout corto de una interfaz de texto normal. La interfaz síncrona sirve para imágenes pequeñas; para documentos grandes conviene una tarea asíncrona con sondeo, lo que reduce de forma notable la tasa de timeouts. Ante un 5xx, reintenta una o dos veces; si sigue fallando, cambia a la solución de respaldo y registra el identificador de solicitud para contrastarlo con el proveedor.

6. Resultado vacío: que la solicitud tenga éxito no significa que el resultado sirva

El "resultado vacío" es el caso que más se diagnostica mal. La interfaz devuelve 200, pero el texto es una cadena vacía, solo tiene puntuación o todos los campos son null. Revisa en este orden:

  • ¿La imagen tiene texto? Abre primero el original y confirma que no es una página en blanco ni una imagen puramente gráfica.
  • ¿La orientación es correcta? Las fotos de teléfono suelen llevar información de rotación y el servidor puede no procesar el EXIF.
  • ¿El texto es demasiado pequeño? Las letras pequeñas de una miniatura de página completa suelen reconocerse al ampliar y recortar.
  • ¿El contraste es bajo? Texto gris claro, sombras, reflejos o transparencias reducen la detección.
  • ¿El idioma coincide? Un modelo entrenado en chino puede devolver solo caracteres sueltos con un documento en ruso o inglés.
  • ¿El diseño queda fuera de lo previsto? Varias columnas, texto vertical, tablas o sellos superpuestos suelen escaparse del OCR tradicional.
  • ¿La interfaz solo devuelve campos estructurados? Algunas ponen el texto completo en otro campo y el código solo lee text.

Si la imagen es nítida, la orientación es correcta y el idioma coincide, pero el resultado sigue vacío, escala el tratamiento: cambia parámetros de preprocesamiento, prueba otro modelo, usa extracción multimodal o deriva a revisión humana. No confíes en la suerte de "llamar otra vez".

La baja confianza también debe tratarse. Define umbrales por campo y envía a una cola de revisión humana los que queden por debajo; valida el formato y haz verificación cruzada de importes, números de documento y fechas. Registra la distribución de confianza para distinguir si la calidad empeora poco a poco o si siempre fue mala.

7. Código reutilizable para el manejo de errores

El ejemplo supone que la interfaz acepta multipart/form-data; ajusta la ruta y los nombres de campo según la documentación del proveedor.

import random
import time
import requests

FATAL = {400, 401, 403, 413, 415}
RETRYABLE = {429, 500, 502, 503, 504}

def ocr_call(image_bytes, api_key, endpoint, max_retries=5):
    last_error = None
    for attempt in range(max_retries):
        try:
            resp = requests.post(
                endpoint,
                headers={"Authorization": f"Bearer {api_key}"},
                files={"file": ("page.png", image_bytes, "image/png")},
                timeout=(5, 90),  # conexión 5 s, lectura 90 s
            )
        except requests.Timeout as exc:
            last_error = exc
        else:
            if resp.status_code in FATAL:
                raise RuntimeError(f"fatal_{resp.status_code}: {resp.text[:300]}")
            if resp.status_code == 200:
                data = resp.json()
                text = (data.get("text") or "").strip()
                if not text:
                    raise ValueError("empty_result: revisa rotación, recorte y formato")
                return data
            if resp.status_code not in RETRYABLE:
                raise RuntimeError(f"unexpected_{resp.status_code}")
            last_error = RuntimeError(resp.text[:300])

        retry_after = resp.headers.get("Retry-After") if "resp" in locals() else None
        wait = float(retry_after) if retry_after else min(2 ** attempt + random.random(), 30)
        time.sleep(wait)

    raise RuntimeError(f"retry_exhausted: {last_error}")

Este código solo aplica retroceso a los errores reintentables, falla de inmediato con 401, 413 y 415, y trata el "resultado vacío" como una anomalía de negocio que requiere intervención humana, no como un error de red.

8. Qué registrar y monitorear

Como mínimo, registra estos campos: identificador de solicitud, código de estado, código de error, duración, dimensiones de imagen, tamaño de archivo, número de reintentos, caracteres reconocidos, confianza media y si se derivó a revisión humana. Agrupa las estadísticas por interfaz y modelo para ver si el problema es un tipo de imagen o un proveedor inestable.

En el monitoreo, configura tres alertas: aumento repentino de la tasa de error, de la tasa de resultados vacíos y de la latencia P95. Mirar solo la duración media oculta la cola larga, y los timeouts de OCR suelen estar precisamente ahí.

9. Preguntas frecuentes

¿Por qué el 401 sigue apareciendo después de cambiar la clave?

Confirma primero el valor que se envía realmente en la cabecera y después si la clave corresponde a la dirección de la interfaz. Las claves de una puerta de enlace y las nativas del proveedor no suelen ser intercambiables, y una variable de entorno puede quedar cacheada en un proceso antiguo.

¿Por qué el 413 sigue apareciendo después de comprimir?

Revisa las dimensiones en píxeles, el número de páginas del PDF y el aumento por Base64. A veces el tamaño no supera el límite, pero la resolución tras la decodificación sí; hay que escalar antes de subir.

¿Por qué el 429 se activa con frecuencia aunque haya reintentos?

Comprueba si todos los clientes reintentan al mismo tiempo y si la concurrencia supera el límite. Añadir jitter, colas y un máximo de concurrencia suele ser más eficaz que aumentar el número de reintentos.

La imagen se ve nítida, ¿por qué el resultado viene vacío?

Revisa primero la orientación, el idioma, el contraste y si el código está leyendo el campo correcto de la respuesta. Una imagen clara pero inclinada, con reflejos o en un idioma que no coincide puede devolver un resultado vacío.

¿Los reintentos se cobran dos veces?

Depende de las reglas de facturación del proveedor y de si la solicitud ya se procesó. Ante un timeout que pudo haber tenido éxito, consulta primero el estado de la tarea o verifica con el identificador de solicitud antes de decidir si reintentar.

Siguiente paso

Cuando el diagnóstico se estabilice, conviene centralizar las llamadas OCR en una sola capa de cliente: timeouts, reintentos, registros y degradación unificados, para que cada módulo de negocio no escriba su propia versión. Si necesitas acceder a varios modelos de visión desde un único punto, puedes conocer ZSQH AI Gateway; el registro está en /sign-up y los modelos y la facturación, en /pricing.

Lecturas relacionadas: