Skip to content

BR-CL-23Use a UN/ECE Recommendation 20 code in unitCode

Every unitCode on a line quantity or price base quantity must be a UN/ECE Rec 20 or Rec 21 code, in upper case. Local abbreviations such as EACH fail.

EN 16931Fatal: the document is invalidCode listsLines and prices

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.

TermMeaningUBL element
BT-130Invoiced quantity unit of measure codecac:InvoiceLine/cbc:InvoicedQuantity/@unitCode
BT-149Item price base quantity: its unit of measure code attributecac: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 PCE on the assumption that it is a standard code, and it is not on this list.
  • Package types are sent without the X prefix 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

  1. List the distinct units your system can put on an invoice line.
  2. 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.
  3. 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.
  4. Write the code in upper case to unitCode on the line quantity, and the same code to cac:Price/cbc:BaseQuantity when that element is present.
  5. 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

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:InvoicedQuantity in an Invoice, cac:CreditNoteLine/cbc:CreditedQuantity in a CreditNote. cac:Price/cbc:BaseQuantity is the same in both. The recorded credit note with unitCode="EACH" on cbc:CreditedQuantity and C62 on 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:InvoicedQuantity inside a cac:CreditNoteLine is 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.

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.