What BR-16 checks
BR-16 requires that an invoice contain at least one invoice line, BG-25: cac:InvoiceLine in UBL, ram:IncludedSupplyChainTradeLineItem in CII. The European core model is line-based by construction: totals are derived from lines, VAT is broken down from lines, and buyer-side automation matches lines against orders. A document that only states "Amount due: 1,190.00 EUR" may be a perfectly good letter, but it cannot be an EN 16931 invoice.
Layer and formats
BR-16 lives in the en16931 core layer and applies to every syntax and every profile claiming core compliance. The only e-invoice documents legitimately without lines are the Factur-X / ZUGFeRD MINIMUM and BASIC WL profiles, which sit below the core and declare so in BT-24.
Why it fails in practice
- Summary exports. The source system holds positions, but the e-invoice export was modelled on the PDF cover sheet and emits only header and totals.
- A profile mismatch. A pipeline built for ZUGFeRD BASIC WL is switched to an EN 16931 profile, and the lineless documents it produces start failing.
- Filtering gone wrong. Zero-amount or fully discounted positions are dropped by an export filter, and for some documents nothing is left.
How to fix it
Emit at least one complete line. A minimal UBL line:
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="C62">1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">1000.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Consulting services March</cbc:Name>
...
</cac:Item>
<cac:Price><cbc:PriceAmount currencyID="EUR">1000.00</cbc:PriceAmount></cac:Price>
</cac:InvoiceLine>
In an InvoiceXML create request the lines are the invoice.lines array; one entry with name, quantity, unit and price is enough, and the request is rejected up front with a clear model error if the array is empty.
The raw rejection vs the InvoiceXML finding
The Schematron report:
<svrl:failed-assert id="BR-16" flag="fatal"
location="/*:Invoice[namespace-uri()='urn:oasis:names:specification:ubl:schema:xsd:Invoice-2'][1]">
<svrl:text>[BR-16]-An Invoice shall have at least one
Invoice line (BG-25)</svrl:text>
</svrl:failed-assert>
The InvoiceXML finding for the same failure:
{
"rule": "BR-16",
"layer": "en16931",
"line": null,
"message": "An invoice must have at least one line item. Add at least one invoice line.",
"btCodes": ["BG-25"],
"fields": ["lines"],
"raw": "[BR-16] EN16931: An Invoice shall have at least one Invoice line (BG-25)"
}
The message is end-user ready and fields points at the request property to fix. For line-scoped rules the mapping goes further: the finding carries the 1-based line number and the path includes the concrete index, for example lines[3].vatInformation.rate, so your UI can highlight the exact row. Clients wanting their own wording localize by the stable rule key.
Check or generate compliant documents
Validate a suspect file in the UBL validator or the XRechnung validator. Generating through POST /v1/create/ubl or POST /v1/create/facturx turns BR-16 into a simple request-shape question: no empty lines array ever becomes XML. The core model behind the rule is covered in EN 16931 explained.
Related rules and identifiers
- BR-01, the sibling core rule requiring a specification identifier
- BR-CO-10, the totals rule summing exactly these lines
- urn:factur-x.eu:1p0:minimum and urn:factur-x.eu:1p0:basicwl, the two profiles that legitimately omit lines