Ir al contenido

Solución de problemas

El puente lanza tres tipos de excepción. La excepción capturada indica qué falló y si conviene reintentar o usar una alternativa. Cada fragmento de mensaje que aparece a continuación está tomado del código fuente.

ExcepciónExtiendeSignificado
CloudflareNotAvailableExceptionNextPDF\Exception\NextPdfExceptionNo se pudo alcanzar el edge o la configuración está incompleta, y no existe ninguna alternativa utilizable.
CloudflareRenderExceptionNextPDF\Exception\NextPdfExceptionEl Worker respondió, pero la representación falló (error HTTP o cuerpo mal formado). Nunca recurre a la alternativa.
InvalidSpkiPinExceptionInvalidArgumentExceptionUna cadena de pin SPKI configurada está mal formada.

CloudflareSecurityPolicy también lanza RuntimeException directamente ante infracciones de las políticas de entrada y de URL. Lo hace antes de enviar cualquier solicitud.

Fragmento de mensajeLanzado porCausaSolución
incomplete (missing worker_url or api_token)Renderizador (mediante la ruta alternativa)workerUrl o apiToken vacíoDefinir ambos; verificarlo con isValid().
HTML input exceeds maximum sizeCloudflareSecurityPolicy::validate()HTML más largo que maxHtmlSizeReducir la entrada o aumentar maxHtmlSize deliberadamente.
Base64 data URI exceeds safety limitCloudflareSecurityPolicy::validate()Un URI data:;base64, estimado en más de 13631488 bytesExternalizar el recurso; no incrustar binarios grandes en línea.
meta-refresh redirect which could cause SSRFCloudflareSecurityPolicy::validate()Una etiqueta <meta http-equiv="refresh">Eliminar la etiqueta; usar una redirección del lado del servidor fuera del HTML representado.
Invalid Worker URLvalidateWorkerUrl()La URL no se puede analizar o carece de scheme/hostProporcionar una URL HTTPS absoluta y completa.
Worker URL must use HTTPSvalidateWorkerUrl()Esquema distinto de HTTPSUsar https://.
private or reserved IP addressesvalidateWorkerUrl()Literal de IP en el rango RFC 1918 / loopback / RFC 3927Apuntar a un endpoint público.
hostname resolves to a private or reserved IPvalidateWorkerUrl()Un registro A/AAAA resuelto se clasifica como private/reservedCorregir el DNS; investigar un posible rebinding.
DNS answer changed since validationassertPinsStillValid()El host se resolvió a una nueva IP entre la comprobación y el envíoVolver a resolver; tratarlo como un posible intento de rebinding.

Son excepciones CloudflareRenderException. El Worker respondió, pero falló la representación en sí. No activan nunca la alternativa local: el edge estaba accesible.

Fragmento de mensajeCausa
Cloudflare Worker returned HTTP <code>: <detail>Estado diferente de 200. El detalle es el campo JSON error o los primeros 200 bytes del cuerpo.
Worker returned empty or invalid PDF dataRespuesta binaria que no empieza por %PDF.
Worker error: <message>Respuesta JSON que incluye un campo error.
JSON response missing "pdf" fieldRespuesta JSON sin campo pdf.
Invalid base64-encoded PDF in JSON responseEl campo pdf no se descodificó desde base64 como bytes que empiezan por %PDF.
Invalid JSON response from WorkerContent-Type: application/json pero el cuerpo no se descodificó como array.
Unexpected Content-Type from Worker: <type>Un 200 cuyo Content-Type no es ni application/pdf ni application/json.

Si se captura uno de estos, conviene inspeccionar los registros del Worker. El fallo está del lado del Worker, no en este puente.

Son excepciones CloudflareNotAvailableException. No se pudo usar el edge y ninguna alternativa produjo un PDF.

Fragmento de mensajeCausaSolución
Cloudflare Worker unavailable: <reason>Error de transporte, alternativa deshabilitadaHabilitar fallbackToLocal y conectar una factoría, o corregir la conectividad.
Artisan is installed but no LocalRendererFactoryInterface was providednextpdf/artisan presente, no se pasó ninguna factoríaPasar un LocalRendererFactoryInterface al constructor.
local Chrome fallback (nextpdf/artisan) is not installedAlternativa habilitada, sin factoría, Artisan ausenteEjecutar composer require nextpdf/artisan y conectar una factoría.

Cuando se proporciona un logger PSR-3 y se ejecuta la ruta alternativa, el puente registra un warning (Cloudflare render failed, attempting fallback) y luego un info (Falling back to local renderer).

SíntomaCausaSolución
InvalidSpkiPinException: Invalid SPKI pin formatUn pin que no tiene la forma sha256/<base64> (ni sha256//<base64>)Corregir la cadena del pin.
cURL transport error (<n>): <msg>Fallo a nivel de cURL (TLS, DNS, tiempo de espera)Inspeccionar el número de error de cURL; si hay pins definidos, confirmar que el SPKI servido sigue estando fijado.
Las representaciones fallan inmediatamente tras la rotación del certificadoEl SPKI del nuevo certificado no está incluido en el conjunto de pinsAñadir el nuevo SPKI como pin de respaldo antes de rotar.
No se usa el transporte fijado pese a que hay pins configuradosNo se proporcionó ningún ResponseFactory PSR-17Pasar un ResponseFactory; el transporte fijado lo requiere.

isAvailable() no lanza nunca una excepción. Devuelve false cuando la configuración no es válida o cuando el sondeo HEAD falla o lanza una excepción. Solo devuelve true cuando el sondeo responde con un estado inferior a 500. Un resultado true es solo un indicio: el POST posterior aún puede fallar con cualquiera de los errores del lado del Worker anteriores. No considerar un sondeo exitoso como garantía.

El limitador ApiProtection mantiene estado en memoria por proceso. Los contadores no sobreviven a un reinicio y no se comparten entre workers ni nodos. Por tanto, si se observa que un cliente queda permitido en un nodo y denegado en otro, es el comportamiento esperado. Anteponer al limitador un almacén compartido para aplicar un límite a escala de clúster.

  • /integrations/cloudflare/security-and-operations/ — el manual operativo y los controles que hay detrás de estos mensajes.
  • /integrations/cloudflare/quickstart/ — la forma canónica de usar try/catch.
  • /integrations/cloudflare/production-usage/ — detalles para conectar la alternativa.