Si envía facturas electrónicas a un cliente B2B alemán en 2026, el archivo cumple ZUGFeRD o será rechazado al recibirse. Lo mismo ocurre en Francia con Factur-X. El formato es un contenedor PDF/A-3 con un XML CII EN 16931 adjunto; generarlo desde cero no es trivial, y validarlo exige un motor de referencia.
Ese motor, en la práctica, es Mustang (mustangproject.org): un proyecto Java de código abierto que extrae el XML embebido de un PDF/A-3 y lo valida contra EN 16931 Schematron. Tiene el soporte más profundo para ZUGFeRD y Factur-X entre las herramientas abiertas, y es lo que ejecutan muchos verificadores independientes.
Este post recorre los fallos que Mustang señala y una forma más rápida de ejecutarlo.
Qué comprueba Mustang realmente
Cuando entrega un PDF Factur-X o ZUGFeRD a Mustang, hace aproximadamente esto:
- Extrae el archivo embebido. PDF/A-3 almacena adjuntos en el árbol de nombres
/EmbeddedFiles. Mustang busca el nombre canónico (factur-x.xmlpara Factur-X,zugferd-invoice.xmlpara ZUGFeRD 2.x) y lee los bytes. - Comprueba AFRelationship. El adjunto debe declararse como
AFRelationship="Alternative"según la base Factur-X / ZUGFeRD. Cualquier otro valor (Source,Data,Supplement) falla. - Comprueba el espacio de nombres XMP y la versión. Factur-X 1.0 usa
urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#. ZUGFeRD 2.x usaurn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#. Un espacio de nombres o una versión incorrectos fallan. - Analiza el XML como Cross-Industry Invoice (CII). Debe ser XML bien formado y empezar con el elemento raíz CII correcto (
rsm:CrossIndustryInvoice). - Ejecuta EN 16931 Schematron. Es el grueso de la validación: unas 200 reglas de negocio sobre semántica de campos, códigos obligatorios, cálculo de totales, lógica de IVA, identificadores de partes, etc.
Pass = la factura es aceptable para cualquier sistema de cuentas por pagar (AP) conforme con EN 16931 en la UE. Fail = la automatización AP del cliente la rechazará al recibirla y el equipo de cuentas por cobrar (AR) tendrá una excepción manual.
Los cinco fallos que más vemos
Aparecen una y otra vez en el lado Mustang de validator cuando los equipos prueban sus primeras facturas electrónicas.
1. AFRelationship equivocado
ERROR: Embedded file factur-x.xml uses AFRelationship="Source",
expected "Alternative".
La especificación PDF permite varios tipos de relación para archivos adjuntos. Factur-X / ZUGFeRD exigen Alternative: el XML adjunto es una representación alternativa del contenido visible del PDF. Si su generador usa Data (valor por defecto habitual en muchas bibliotecas), Mustang falla de inmediato. El PDF visual todavía se renderiza, pero los datos estructurados no sirven para el sistema AP.
2. Namespace XMP incorrecto o ausente
ERROR: XMP metadata missing fx:DocumentType or fx:DocumentFileName under
namespace urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#.
El paquete XMP del PDF debe declarar qué perfil Factur-X es (MINIMUM, BASIC, EN 16931, EXTENDED) y qué nombre de archivo debe buscarse. Es fácil omitirlo al escribir el contenedor PDF/A-3 a mano; el endpoint /api/v1/e-invoice/render de gPdf lo emite automáticamente.
3. XML CII bien formado, pero falla EN 16931 Schematron
ERROR: BR-CO-25 — In an invoice (BR-01) the
ram:SpecifiedTradePaymentTerms/ram:DueDateDateTime is required when
ram:DocumentTypeCode is 380.
Aquí vive la mayoría de fallos reales. El XML es sintácticamente válido; fallan las reglas de negocio. Las reglas EN 16931 Schematron tienen IDs estables (BR-01, BR-CO-25, etc.) consultables en la especificación. Comunes:
- BR-01: la factura debe tener número único.
- BR-04: debe tener fecha de emisión.
- BR-05: debe tener un código de tipo de factura.
- BR-CO-25: las condiciones de pago son obligatorias cuando el tipo de documento es “Commercial invoice”.
- BR-Z-01: el código de categoría de IVA debe ser uno de
S,Z,E,AE,K,G,O,L,M.
Corrija los datos de origen, reconstruya y vuelva a validar.
4. El contenedor PDF/A no valida
INFO: CII XML extracted and validates against EN 16931.
ERROR: PDF/A-3b conformance check failed: missing Output Intent.
En este caso Mustang aprueba el XML, pero falla el PDF/A-3 subyacente. Causa típica: alguien generó bien el XML pero emitió un PDF normal en vez de PDF/A-3. El archivo embebido existe, pero no se cumplen las reglas archivísticas. El validador de gpdf.com/validator/ lo detecta ejecutando veraPDF en paralelo: el fallo aparece en la columna de veraPDF mientras Mustang muestra que el XML ha pasado.
5. La codificación y la declaración no coinciden
ERROR: XML declares <?xml version="1.0" encoding="UTF-8"?> but the
embedded byte stream is UTF-8 with BOM. Mustang strict mode rejects BOM.
Es más común de lo que parece cuando la herramienta XML emite UTF-8 BOM y luego se incrusta sin procesarlo. La solución: eliminar el BOM antes de embeberlo. El endpoint de factura electrónica de gPdf normaliza esto.
Cómo ejecutar Mustang sin instalar Java
Instalar Java + Mustang CLI está bien para una comprobación puntual. Para verificación continua — cada factura generada, cada ejecución de CI que afirma conformidad — es fricción innecesaria.
gpdf.com/validator/ ejecuta Mustang en el navegador:
- Arrastre el PDF Factur-X / ZUGFeRD al área de carga.
- El validador extrae el XML embebido y ejecuta el motor Schematron de Mustang (compilado a JavaScript / WebAssembly y ejecutado en Cloudflare Worker).
- El informe de Mustang vuelve junto al informe PDF/A-3 de veraPDF, porque ambas capas deben pasar.
- Descargue el informe JSON como evidencia de QA.
Sin login. Sin cuota. El mismo Mustang que instalaría vía Maven, servido como servicio público gratuito.
TL;DR
Mustang señala 5 fallos comunes; la mayoría se reduce a “el archivo fue generado por una herramienta que no emite un PDF/A-3 Factur-X / ZUGFeRD completo”. La E-invoice API de gPdf lo emite en una llamada. validator verifica el resultado con Mustang + veraPDF en paralelo.
La mayoría de errores que atrapa Mustang están en el contenedor o en AFRelationship, no solo en la semántica XML. Generar bien el archivo resuelve gran parte; el validador es el recibo que lo prueba.