Aller au contenu

Dépannage de NextPDF Gotenberg

Le pont échoue de façon explicite et précoce. Chaque échec prend la forme d’une exception typée, dont le message indique la cause. Cette page en fait le catalogue. Pour chaque échec, elle précise le type d’exception, le fragment de message que tu verras, le déclencheur exact dans le chemin de code et le correctif.

Les familles d’exceptions sont les suivantes :

  • GotenbergConvertException — échec de la couche de conversion (configuration, transport ou réponse).
  • RuntimeException — échec de la couche de validation levé par la politique de sécurité, avant tout trafic réseau.
  • ValueError — une extension de fichier non reconnue.
  • InvalidSpkiPinException — une chaîne d’épinglage TLS mal formée.

« Invalid Gotenberg configuration : apiUrl is empty »

Section intitulée « « Invalid Gotenberg configuration : apiUrl is empty » »
  • Type : GotenbergConvertException
  • Déclencheur : convertFile() ou convertString() a été appelé alors que GotenbergConfig::isValid() est faux. Cela se produit lorsque apiUrl est une chaîne vide.
  • Correctif : fournis une URL HTTPS non vide. Si tu construis la configuration avec fromArray(), note qu’elle remplace silencieusement un api_url manquant ou non textuel par ''. Valide la source de ta configuration pendant l’amorçage.

Ces échecs proviennent de la politique de sécurité, qui protège contre la falsification de requête côté serveur (SSRF). Ils sont levés avant l’envoi de toute requête. Il s’agit de simples RuntimeException.

« Gotenberg API URL must use HTTPS (got : http) »

Section intitulée « « Gotenberg API URL must use HTTPS (got : http) » »
  • Déclencheur : le schéma de l’URL configurée n’est pas https. La vérification ne tient pas compte de la casse ; HTTPS:// est donc accepté.
  • Correctif : place Gotenberg derrière TLS et configure le point de terminaison HTTPS. Le trafic HTTP en clair est rejeté, même en développement local.

« Invalid Gotenberg API URL : unable to parse »

Section intitulée « « Invalid Gotenberg API URL : unable to parse » »
  • Déclencheur : l’URL ne peut pas être décomposée en un schéma et un hôte.
  • Correctif : fournis une URL absolue syntaxiquement valide, par exemple https://gotenberg.example.com:3000.

« Gotenberg API URL must not resolve to a private or reserved IP address »

Section intitulée « « Gotenberg API URL must not resolve to a private or reserved IP address » »
  • Déclencheur : l’hôte est une adresse IP littérale privée ou réservée, ou un nom d’hôte qui se résout (via tous les enregistrements A/AAAA) vers au moins une adresse privée ou réservée. Cela bloque les plages RFC 1918, les adresses de bouclage et les adresses lien-local.
  • Correctif : pointe le pont vers une adresse de service publique et routable, ou correctement segmentée. Si ton instance Gotenberg se trouve intentionnellement sur un réseau privé, le garde-fou SSRF du pont rejette cette adresse par conception. Expose-la via une adresse acceptée par le garde-fou, puis protège ce chemin avec des contrôles réseau et une authentification. Voir /integrations/gotenberg/security-and-operations/.

« Gotenberg API URL DNS answer changed since validation — possible DNS rebinding attack »

Section intitulée « « Gotenberg API URL DNS answer changed since validation — possible DNS rebinding attack » »
  • Déclencheur : entre la validation initiale et la requête, une nouvelle résolution DNS a renvoyé une adresse qui ne figurait pas dans l’ensemble validé à l’origine.
  • Correctif : le garde-fou time-of-check/time-of-use se déclenche. Examine le DNS de l’hôte. Une cause légitime peut être un répartiteur de charge qui alterne les adresses. Une cause malveillante peut être une attaque de DNS rebinding. Utilise une adresse stable ou un nom dont l’ensemble d’enregistrements reste stable pour le point de terminaison Gotenberg.

Ces échecs sont levés par la politique de sécurité avant la requête. Chacun est une simple RuntimeException, sauf indication contraire.

  • Type : GotenbergConvertException
  • Déclencheur : convertFile() n’a pas pu résoudre le chemin canonique, ou le chemin résolu n’est pas un fichier régulier lisible. Un répertoire déclenche aussi cet échec.
  • Correctif : passe le chemin d’un fichier existant et lisible. Le chemin est d’abord résolu avec realpath(), ce qui neutralise aussi les tentatives de traversée de répertoires.

« File size ( bytes) exceeds maximum allowed size ( bytes) »

Section intitulée « « File size ( bytes) exceeds maximum allowed size ( bytes) » »
  • Déclencheur : l’entrée dépasse maxFileSize (par défaut 52 428 800 octets = 50 MiB).
  • Correctif : augmente maxFileSize si le document en a réellement besoin, ou rejette l’envoi en amont. Garde le plafond aussi bas que tes documents réels le permettent. C’est la seule limite de ressources intégrée au pont.

Le nom de fichier est filtré. Pour les conversions de fichiers, le nom de fichier correspond au nom de base du chemin résolu ; pour convertString(), c’est celui que tu fournis. Chacun de ces cas est une RuntimeException :

Fragment de messageDéclencheur
must not be emptynom de fichier vide
path traversal sequences (..)le nom contient ..
forward slashesle nom contient /
backslashesle nom contient \
null bytesle nom contient un octet NUL
control charactersle nom contient un caractère de contrôle ASCII (0–31)
  • Correctif : passe un nom de base propre. Pour convertString(), fournis un nom simple tel que report.docx. Il sert à la détection du format et comme nom de fichier pour l’envoi multipart, pas comme chemin.
  • Type : ValueError
  • Déclencheur : l’extension du fichier n’est pas l’une de docx, xlsx, pptx, odt, ods, odp (insensible à la casse, point initial toléré).
  • Correctif : ne convertis que les six formats reconnus. Le pont ne reconnaît pas les anciens formats binaires (.doc, .xls, .ppt), .rtf, .csv, le texte brut ni les images. Convertis ces entrées vers un format reconnu avant d’appeler le pont, ou traite-les par un autre chemin.

Tous ces échecs sont des GotenbergConvertException.

  • Déclencheur : le client PSR-18 (ou le transport cURL épinglé) a levé une exception lors de l’envoi de la requête. Il peut s’agir d’un refus de connexion, d’un dépassement de délai, d’un échec de poignée de main TLS ou d’une non-concordance d’épinglage.
  • Code d’exception : le code de l’exception sous-jacente du client.
  • Cause : l’exception PSR-18 d’origine du client est attachée comme exception précédente.
  • Correctif : vérifie quatre points : l’accessibilité du service avec isAvailable(), le chemin réseau, la chaîne TLS et, si l’épinglage est configuré, la correspondance entre le SubjectPublicKeyInfo (SPKI) actuel du serveur et l’un des épinglages configurés. Une non-concordance d’épinglage après une rotation de certificat est la cause classique. Voir la procédure de rotation dans /integrations/gotenberg/security-and-operations/.
  • Déclencheur : l’appel curl_exec du transport cURL épinglé a échoué avec un numéro d’erreur cURL non nul, ou a renvoyé un corps non textuel.
  • Correctif : le numéro d’erreur cURL identifie la cause (TLS, résolution, dépassement de délai, épinglage). Un échec d’épinglage apparaît ici lorsque CURLOPT_PINNEDPUBLICKEY rejette le certificat. Confirme que les épinglages configurés et l’adresse résolue sont à jour.

« Gotenberg conversion failed with HTTP  :  »

Section intitulée « « Gotenberg conversion failed with HTTP  :  » »
  • Déclencheur : le statut de la réponse n’était pas 200. Le corps est inclus, tronqué aux 500 premiers caractères, et des points de suspension sont ajoutés lorsqu’il est plus long.
  • Correctif : lis le corps inclus. Le message d’erreur de Gotenberg explique pourquoi la conversion a été rejetée : contenu de document non pris en charge, échec interne de LibreOffice ou rejet d’authentification sur un 401 ou 403. Un 401/403 signifie que l’apiKey est manquante ou incorrecte. Un 5xx est un échec côté service et constitue un candidat à une nouvelle tentative bornée.

« Unexpected Content-Type from Gotenberg : (expected application/pdf) »

Section intitulée « « Unexpected Content-Type from Gotenberg : (expected application/pdf) » »
  • Déclencheur : le statut était 200 mais le Content-Type de la réponse ne contenait pas application/pdf.
  • Correctif : cela signifie généralement qu’un proxy ou une passerelle a renvoyé une page d’erreur HTML ou une redirection avec un 200. Le pont désactive délibérément le suivi des redirections sur le transport épinglé, afin qu’un 3xx ne soit pas silencieusement poursuivi vers un hôte non vérifié. Un corps reçu avec le mauvais type signale que quelque chose interfère entre toi et Gotenberg. Examine le chemin réseau.

« Response body does not start with %PDF header — invalid PDF data »

Section intitulée « « Response body does not start with %PDF header — invalid PDF data » »
  • Déclencheur : le statut est 200, le Content-Type est acceptable, mais le corps ne commence pas par la signature %PDF.
  • Correctif : l’amont a renvoyé quelque chose qui n’est pas un PDF malgré les en-têtes. Traite la réponse comme non fiable et examine le service. N’écris pas le corps sur le disque. Le pont refuse de le renvoyer comme résultat.

« Invalid SPKI pin format : (expected sha256/) »

Section intitulée « « Invalid SPKI pin format : (expected sha256/) » »
  • Type : InvalidSpkiPinException
  • Déclencheur : une chaîne d’épinglage configurée ne commence ni par sha256/ ni par sha256//.
  • Correctif : formate chaque épinglage sous la forme sha256/<base64-encoded-spki-hash>. Le transport accepte aussi la forme native cURL sha256//<base64>. Génère la valeur à partir du SubjectPublicKeyInfo du certificat du serveur, et non à partir du certificat entier.

isAvailable() renvoie false sans effectuer d’appel réseau lorsque l’URL est vide, n’est pas HTTPS ou se résout vers une adresse private/reserved. Elle renvoie aussi false en cas d’erreur réseau, quelle qu’elle soit, ou lorsque /health renvoie 500 ou plus ; dans ces cas, elle intercepte l’erreur au lieu de la lever. Vérifie, dans l’ordre :

  1. L’URL configurée est non vide et utilise HTTPS.
  2. L’hôte ne se résout vers aucune adresse private/reserved (le garde-fou SSRF la rejette même pour la sonde).
  3. <apiUrl>/health est joignable depuis l’hôte de l’application et renvoie un statut inférieur à 500.
  • /integrations/gotenberg/configuration/ — chaque option et les règles de sélection du transport.
  • /integrations/gotenberg/production-usage/ — la politique de nouvelle tentative et le contrat de gestion des échecs.
  • /integrations/gotenberg/security-and-operations/ — le modèle SSRF et la rotation des épinglages.
  • /integrations/gotenberg/quickstart/ — l’ordre exhaustif des captures d’exceptions en contexte.