Les défaillances d'une API OCR se répartissent en trois familles : la requête n'est jamais acceptée (401, 413, 415), la requête est limitée ou expire (429, 5xx), ou la requête réussit mais le résultat est inexploitable (texte vide, caractères parasites, faible confiance). Les deux premières se diagnostiquent à partir du code d'état ; la troisième est la plus souvent prise à tort pour une « panne de l'interface ».

Cet article propose un ordre de diagnostic par symptôme, des méthodes de prétraitement des images, une stratégie de nouvelles tentatives et les champs à journaliser, puis un exemple de code de gestion des erreurs directement réutilisable.

Note : les interfaces OCR, codes d'erreur et règles de quota varient fortement d'un fournisseur à l'autre. Cet article décrit les comportements courants observés en octobre 2026 ; la documentation du fournisseur et les réponses réelles font foi. Les noms OpenAI, Google, Microsoft, Alibaba Cloud, Tencent Cloud, Baidu AI Cloud, Tesseract et PaddleOCR sont des marques ou des noms de produits de leurs titulaires respectifs ; ils ne sont cités qu'à titre technique.

1. Conserver d'abord quatre éléments de preuve

Avant de relancer, enregistrez ces informations :

  • le code d'état HTTP et les champs error.code et error.message du corps de réponse ;
  • l'identifiant de requête ou x-request-id présent dans les en-têtes ;
  • le format d'origine de l'image, sa taille de fichier, ses dimensions en pixels et l'orientation EXIF ;
  • l'heure de l'appel, l'adresse de l'interface et le nom du modèle.
Code HTTP Signification courante À vérifier en premier
400 Paramètre ou contenu d'image invalide Base64, URL, noms de champs, image corrompue
401 Échec de l'authentification Clé absente, expirée ou contenant des espaces
403 Droits insuffisants ou quota restreint Droits du modèle, état du projet, solde du compte
413 Corps de requête ou fichier trop volumineux Taille du fichier, dimensions, nombre de pages PDF
415 Type de média non pris en charge Content-Type, extension, encodage réel
429 Limitation de débit ou de concurrence QPS, requêtes simultanées, Retry-After
500/502/503/504 Défaillance ou délai côté amont Nouvelle tentative, repli, page d'état du service

2. 401 et 403 : identité d'abord, droits ensuite

Un 401 signifie que le serveur ne reconnaît pas la clé. Causes fréquentes : en-tête Authorization: Bearer absent, clé copiée avec un espace ou un saut de ligne, variable d'environnement vide, clé renouvelée, ou clé d'une plateforme envoyée à l'adresse d'une autre.

Diagnostiquez avec une requête minimale, sans deviner au milieu du flux métier. Vérifiez la valeur réellement envoyée dans l'en-tête, pas seulement le fichier de configuration. Un 403 indique en général une clé valide mais sans droit sur le modèle ou l'interface, un compte plafonné ou un projet désactivé.

Autre point : les clés d'une passerelle et celles du fournisseur d'origine ne se mélangent généralement pas. Lors d'un changement d'adresse, vérifiez ensemble la clé, le nom du modèle et le chemin de la requête.

3. 413 et 415 : fichier trop volumineux, format incorrect

Un 413 ne signifie pas « le contenu de l'image est illisible », mais que la requête est rejetée au niveau du transport. Déclencheurs courants :

  • une image dépasse la limite de taille de l'interface ;
  • les dimensions sont trop grandes et la mémoire dépasse la limite après décodage ;
  • le PDF contient trop de pages, ou plusieurs pages sont envoyées en une fois ;
  • l'encodage Base64 gonfle le volume d'environ un tiers, faisant dépasser une limite tout juste atteinte.

Un 415 concerne le plus souvent le format : l'interface n'accepte que JPG et PNG, mais vous envoyez du HEIC, TIFF ou BMP ; l'extension est JPG alors que le contenu réel est du WebP ; ou le Content-Type vaut application/json alors que l'interface attend multipart/form-data.

Ordre de prétraitement recommandé :

  1. Lire l'image avec une bibliothèque graphique et confirmer le format réel, sans faire confiance à l'extension.
  2. Redimensionner proportionnellement selon le côté long, par exemple vers 2 000 à 3 000 pixels pour commencer.
  3. Corriger l'orientation EXIF, pour éviter un texte couché qui produit un résultat vide.
  4. Convertir vers un format accepté et régler la qualité de compression sans rendre le texte flou.
  5. Découper les PDF multipages et traiter page par page, ou utiliser une interface qui accepte le document entier.
  6. Consigner le volume et les dimensions avant et après traitement, pour identifier l'étape qui dépasse la limite.

Ne compressez pas une image jusqu'à la rendre illisible pour passer un 413. Après compression, les traits des caractères se collent : l'interface renvoie un succès, mais la qualité est mauvaise.

4. 429 : limitation, concurrence et rythme des tentatives

Un 429 signifie « trop de requêtes, ou trop vite ». Les dimensions courantes sont le nombre de requêtes par seconde, par minute, la concurrence et les quotas calculés en tokens ou en pages. Même si le total reste sous la limite, un pic instantané peut déclencher la limitation.

Principes de traitement :

  • lire Retry-After et attendre la durée indiquée ;
  • sinon, appliquer un backoff exponentiel avec un jitter aléatoire, pour éviter que tous les clients réessaient simultanément ;
  • ne réessayer que les 429 et les 5xx ; réessayer un 401, 413 ou 415 est inutile ;
  • fixer un nombre maximal de tentatives et un délai global, pour éviter l'accumulation des tâches ;
  • placer les pics de trafic dans une file et lisser l'envoi selon la capacité du serveur.

Réessayer plus n'est pas toujours mieux. Pour une interface facturée à l'appel, la facturation des échecs dépend des règles du fournisseur ; des tentatives aveugles peuvent augmenter le coût.

5. Délais d'attente et 5xx : réseau ou amont

Distinguez le délai de connexion et le délai de lecture. Un délai de connexion révèle généralement un problème de réseau, de DNS, de proxy ou de pare-feu ; un délai de lecture indique que la requête est arrivée mais que le traitement est long, fréquent avec de grandes images, des PDF multipages ou une file en amont.

Définissez un délai spécifique pour les requêtes OCR, sans reprendre le délai court des interfaces de texte. Une interface synchrone convient aux petites images ; pour les gros documents, préférez une tâche asynchrone avec interrogation périodique, ce qui réduit nettement le taux d'expiration. Pour les 5xx, réessayez une à deux fois, puis basculez sur le plan de repli en conservant l'identifiant de requête pour vérifier auprès du fournisseur.

6. Résultat vide : une requête réussie n'est pas un résultat exploitable

Le « résultat vide » est la catégorie la plus facile à mal interpréter. L'interface renvoie 200, mais le texte est vide, ne contient que de la ponctuation, ou tous les champs valent null. Ordre de diagnostic :

  • L'image contient-elle du texte : ouvrez d'abord l'original pour vérifier qu'il ne s'agit pas d'une page blanche ou d'une image pure.
  • L'orientation est-elle correcte : les photos de téléphone portent souvent une rotation que le serveur peut ne pas appliquer via EXIF.
  • Le texte est-il trop petit : un texte minuscule dans une vignette de page entière devient souvent lisible après recadrage et agrandissement.
  • Le contraste est-il trop faible : texte gris clair, ombre, reflet ou transparence dégradent le rappel.
  • La langue correspond-elle : un modèle chinois appliqué à un document russe ou anglais peut ne produire que quelques caractères.
  • La mise en page sort-elle du cadre : colonnes multiples, écriture verticale, tableaux et tampons superposés font échouer l'OCR classique.
  • L'interface ne renvoie-t-elle que des champs structurés : certains services placent le texte complet dans un autre champ, alors que le code ne lit que text.

Si l'image est nette, correctement orientée et dans la bonne langue, mais que le résultat reste vide, passez à l'étape suivante : modifier les paramètres de prétraitement, changer de modèle, utiliser une extraction multimodale ou basculer vers une vérification humaine. N'espérez pas qu'un nouvel appel suffira.

La faible confiance doit aussi être traitée. Fixez un seuil par champ et envoyez les valeurs inférieures à une file de vérification humaine ; validez le format des montants, numéros de pièce d'identité et dates, avec des contrôles croisés. Journalisez la distribution des scores de confiance pour distinguer une dégradation progressive d'une qualité durablement mauvaise.

7. Code de gestion des erreurs réutilisable

L'exemple suppose que l'interface accepte multipart/form-data ; adaptez le chemin et les noms de champs à la documentation du fournisseur.

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),  # connexion 5 s, lecture 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: check rotation, crop and format")
                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}")

Ce code n'applique un backoff qu'aux erreurs réessayables, échoue immédiatement sur 401, 413 et 415, et traite le « résultat vide » comme une anomalie métier nécessitant une intervention humaine, non comme une erreur réseau.

8. Journaux et supervision

Consignez au minimum : identifiant de requête, code d'état, code d'erreur, durée, dimensions de l'image, taille du fichier, nombre de tentatives, nombre de caractères reconnus, confiance moyenne et passage éventuel à une vérification humaine. Agrégez par interface et par modèle pour distinguer un type d'image problématique d'un amont instable.

Trois alertes sont utiles : hausse brutale du taux d'erreur, hausse brutale du taux de résultats vides, hausse brutale de la latence P95. Surveiller seulement la durée moyenne masque la queue longue, or les expirations OCR se produisent souvent dans cette queue.

9. Questions fréquentes

J'ai changé la clé et le 401 persiste ?

Vérifiez d'abord la valeur réellement envoyée dans l'en-tête, puis la correspondance entre la clé et l'adresse de l'interface. Une clé de passerelle et une clé de fournisseur ne se remplacent généralement pas ; une variable d'environnement peut aussi être mise en cache par un ancien processus.

Le 413 persiste après compression ?

Contrôlez les dimensions en pixels, le nombre de pages PDF et le gonflement Base64. Parfois le volume reste sous la limite, mais la résolution après décodage dépasse celle de l'interface : il faut redimensionner avant l'envoi.

Le 429 revient malgré les tentatives ?

Regardez si tous les clients réessaient en même temps et si la concurrence dépasse le quota. Ajouter du jitter, une file et un plafond de concurrence est souvent plus efficace que d'augmenter le nombre de tentatives.

L'image est lisible, pourquoi le résultat est-il vide ?

Vérifiez en priorité l'orientation, la langue, le contraste et le champ de réponse réellement lu. Une image nette mais inclinée, réfléchissante ou dans une langue non couverte peut encore renvoyer un résultat vide.

Les tentatives peuvent-elles être facturées deux fois ?

Cela dépend des règles de facturation et du traitement effectif de la requête. Pour une requête expirée qui a peut-être réussi, consultez d'abord l'état de la tâche ou l'identifiant de requête avant de décider de réessayer.

Et ensuite

Une fois le diagnostic stabilisé, regroupez les appels OCR dans une couche cliente unique : délais, tentatives, journaux et repli communs, pour éviter que chaque module métier réécrive sa propre logique. Pour un accès unifié à plusieurs modèles de vision, découvrez ZSQH AI Gateway ; l'inscription se fait sur /sign-up, les modèles et la facturation sur /pricing.

Lectures associées :