The short answer
BR-CL-23 fails when a unitCode attribute holds something that is not on the unit of measure code list shipped with the validation artefacts. Replace your local unit abbreviation with the UN/ECE Recommendation 20 code that means the same thing: KGM for kilograms, HUR for hours, C62, H87 or EA for countable items.
The finding location names the quantity element with the bad code. If you change the unit on the line quantity, change it on cac:Price/cbc:BaseQuantity too, because Peppol requires the two to agree.
What the rule checks
The rule runs on cbc:InvoicedQuantity, cbc:CreditedQuantity and cbc:BaseQuantity, each time the element has a unitCode attribute, and looks the value up in a fixed list. That list combines UN/ECE Recommendation 20, the units of measure, with Recommendation 21, the package types, whose codes are written with an X in front: XPK is accepted and a bare PK is not.
The match is exact and case-sensitive. c62 and h87 fail where C62 and H87 pass. Abbreviations that look plausible but are not on the list also fail: EACH, PCE, pcs, KG and HR are all rejected. An empty unitCode="" fails as well.
Each quantity is a separate finding. A line with the same bad code on the quantity and on the price base quantity reports the rule twice.
A quantity with no unitCode attribute at all is outside this rule, and the UBL schema allows it. On the line quantity the omission is reported by BR-23 instead. On cbc:BaseQuantity the attribute can be left out without any finding.
| Term | Meaning | UBL element |
|---|---|---|
| BT-130 | Invoiced quantity unit of measure code | cac:InvoiceLine/cbc:InvoicedQuantity/@unitCode |
| BT-149 | Item price base quantity: its unit of measure code attribute | cac:InvoiceLine/cac:Price/cbc:BaseQuantity/@unitCode |
How an integration ends up here
Possible causes, from the shape of the rule rather than from measured usage:
- The unit is copied straight from the product master, which uses the abbreviations of the ERP or the warehouse and not UN/ECE codes.
- A mapping table exists but covers only the units in use when it was written, and a new unit falls through unmapped.
- Codes pass through a step that lower-cases them.
- The system uses a widely seen abbreviation such as
PCEon the assumption that it is a standard code, and it is not on this list. - Package types are sent without the
Xprefix that marks them as Recommendation 21 codes. - Service lines have no unit in the source, and a made-up default is written to fill the attribute.
How to fix it
- List the distinct units your system can put on an invoice line.
- Map each one to the Recommendation 20 code with the same meaning, or to the
X-prefixed Recommendation 21 code for a package type. Keep the mapping as data so a new unit is a new row and not a code change. - Do not collapse unknown units into
C62. The unit is part of what was sold; a quantity of 2 in kilograms and 2 of one item are different statements. - Write the code in upper case to
unitCodeon the line quantity, and the same code tocac:Price/cbc:BaseQuantitywhen that element is present. - Fail the export for a unit with no mapping so the gap is found when the unit is introduced.
Validate your corrected invoice
Before and after
These are fragments, not complete documents. The complete synthetic documents they come from are linked below.
Line of the failing invoice: EACH is not a Recommendation 20 code
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="EACH">2</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="GBP">25.00</cbc:LineExtensionAmount>
<!-- item omitted from this fragment -->
<cac:Price>
<cbc:PriceAmount currencyID="GBP">12.5</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="C62">1</cbc:BaseQuantity>
</cac:Price>
</cac:InvoiceLine>Line of the corrected invoice: C62 on both quantities
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="C62">2</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="GBP">25.00</cbc:LineExtensionAmount>
<!-- item omitted from this fragment -->
<cac:Price>
<cbc:PriceAmount currencyID="GBP">12.5</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="C62">1</cbc:BaseQuantity>
</cac:Price>
</cac:InvoiceLine>Only the unitCode of cbc:InvoicedQuantity differs: EACH in the failing invoice, C62 in the corrected one. The failing document also reports PEPPOL-EN16931-R130, located at cbc:BaseQuantity: that Peppol rule requires the price base quantity to use the same unit as the line quantity, and C62 is not EACH. It is a consequence of changing one attribute and not the other. With EACH on both quantities the document reports BR-CL-23 twice and PEPPOL-EN16931-R130 not at all.
What the validator reported
- The failing invoice reports BR-CL-23 and
PEPPOL-EN16931-R130. The corrected document passes every layer with no findings.Download the failing XMLDownload the corrected XML - The failing credit note reports BR-CL-23 and
PEPPOL-EN16931-R130. 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
- The line quantity is named differently in the two document types:
cac:InvoiceLine/cbc:InvoicedQuantityin anInvoice,cac:CreditNoteLine/cbc:CreditedQuantityin aCreditNote.cac:Price/cbc:BaseQuantityis the same in both. The recorded credit note withunitCode="EACH"oncbc:CreditedQuantityandC62on the base quantity reports the same two rules as the invoice. - A mapper that builds credit notes by renaming invoice elements has to rename the quantity as well: a
cbc:InvoicedQuantityinside acac:CreditNoteLineis rejected by the XSD layer. Once the element is right, the code list and the behaviour of this rule are identical. - The code list is the one published with the pinned EN 16931 artefacts. Look codes up in that list or in the UN/ECE recommendations themselves; this page does not reproduce them.
Related rules
- PEPPOL-EN16931-R121 checks that the price base quantity carrying this unit is greater than zero
- PEPPOL-EN16931-R120 checks the line net amount calculated from the quantity and price
- BR-CL-04 is the equivalent code list check for the invoice currency
- BR-25 requires an item name on the same line
- Browse every rule in the reference
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-20.1: source checked 2026-09-20, explanation last updated 2026-09-20.
The official definition of BR-CL-23 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.
