The short answer
BR-21 fails for a line whose own cbc:ID has no text. In the recorded example the only cac:InvoiceLine opens with <cbc:ID></cbc:ID>. Write the line number, or another reference that tells this line apart from the others, into that element on every cac:InvoiceLine or cac:CreditNoteLine.
Deleting the element is not a way out. The UBL schema requires a cbc:ID in every line, so a line without one is refused at the XSD layer and none of the business rules are reported.
What the rule checks
The rule is evaluated once per line, on each cac:InvoiceLine in an invoice and each cac:CreditNoteLine in a credit note. It reads only the cbc:ID that belongs directly to the line and passes when that element holds at least one character other than whitespace.
Empty and blank are treated alike. When tried, an open and close tag with nothing between them, a self-closing <cbc:ID/> and an element holding three spaces each reported BR-21 together with PEPPOL-EN16931-R008. An empty cbc:ID carrying a schemeID attribute failed in the same way, because an attribute is not content.
A line with no cbc:ID at all never reaches this rule. When tried on both an invoice and a credit note, the XSD layer refused the document and the EN 16931 and Peppol layers were skipped.
Beyond being present, the value is not examined. LINE-A passes as readily as 1, and when tried, an invoice with two lines both numbered 1 passed every layer. EN 16931 describes the line identifier as unique within the document, so keep it unique even though the validator does not test that.
| Term | Meaning | UBL element |
|---|---|---|
| BT-126 | Invoice line identifier | cac:InvoiceLine/cbc:ID (cac:CreditNoteLine/cbc:ID in a credit note) |
| BG-25 | Invoice line | cac:InvoiceLine (cac:CreditNoteLine in a credit note) |
How an integration ends up here
Possible causes, from the shape of the rule rather than from measured usage:
- Line numbers are assigned when the invoice is posted, and the XML is built from a draft in which the field is still blank.
- Lines added by the export itself, such as a delivery charge or a rounding line, have no row in the source table and so no line number to copy.
- A null line reference is serialised as an empty element instead of being filled from the position of the line.
- The identifier is read from a field that exists only for some line types, such as an order line reference, and it is empty for free-text lines.
How to fix it
- Use the finding location, such as
cac:InvoiceLine[1], to see which line is affected. Each line with an empty identifier gives its own finding. - Take the identifier from the source line: its line number or sequence on the invoice as issued. If the source has none, number the lines in document order,
1,2,3, when the XML is built. - Keep the identifiers unique within the document and the same as on any PDF or copy of the invoice, so the buyer can quote a line back to you.
- Leave
cbc:IDwhere the schema places it, at the start of the line before anycbc:Noteand the quantity. Moving it or dropping it turns this finding into an XSD failure.
Validate your corrected invoice
Before and after
These are fragments, not complete documents. The complete synthetic documents they come from are linked below.
Fragment of the failing invoice: the line identifier is present but empty
<cac:InvoiceLine>
<cbc:ID></cbc:ID>
<cbc:InvoicedQuantity unitCode="C62">2</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="GBP">25.00</cbc:LineExtensionAmount>
<!-- item and price omitted from this fragment -->
</cac:InvoiceLine>Fragment of the corrected invoice: the line is numbered 1
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="C62">2</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="GBP">25.00</cbc:LineExtensionAmount>
<!-- item and price omitted from this fragment -->
</cac:InvoiceLine>Only the line cbc:ID differs: empty in the failing invoice, 1 in the corrected one. The failing document also reports PEPPOL-EN16931-R008, located at that cbc:ID rather than at the line, because Peppol rejects any element without content. Writing the line number clears both findings.
What the validator reported
- The failing invoice reports BR-21 and PEPPOL-EN16931-R008. The corrected document passes every layer with no findings.Download the failing XMLDownload the corrected XML
Recorded on phive 12.1.0 / phive-rules-peppol 4.5.6 / Saxon-HE 12.10, the engine behind the free validator, using synthetic data. A recorded result is regression evidence for these documents; it is not a certification.
Where it applies
- Applies to
cac:InvoiceLinein a UBLInvoiceand tocac:CreditNoteLinein aCreditNote. When tried on a credit note, an empty line identifier reportedBR-21atcac:CreditNoteLine[1]andPEPPOL-EN16931-R008at itscbc:ID, the same pair as on the invoice. - Other
cbc:IDelements are not read by this rule: not the document number directly under the root, whichBR-02covers, and not the ones nested inside the line, such as the VAT category code incac:ClassifiedTaxCategory.
Related rules
- PEPPOL-EN16931-R008 is reported at the same element when the line identifier is present but empty
- BR-02 is the equivalent presence check for the document number under the root
- BR-22 requires a quantity on the same line
- BR-25 requires an item name on every line
- Browse every rule in the reference
- Background: Understanding EN 16931 validation errors
Scope and source
Written for Peppol BIS Billing 3.0.21 (May 2026), EN 16931 1.3.16, as applied to UBL 2.1 Invoice and CreditNote documents. Other profiles, syntaxes and releases can define this identifier differently. Guidance version 2026-09-24.1: source checked 2026-09-24, explanation last updated 2026-09-24.
The official definition of BR-21 carries the normative wording and test. This page is our explanation of it, not a copy.
Guidance does not change the engine verdict. Fixing this finding does not mean the document passes every layer, and validation does not certify legal or tax compliance or transmit a document over Peppol.
