Skip to content

BR-23: Add the unitCode attribute to the line quantity

The cbc:InvoicedQuantity or cbc:CreditedQuantity on each line must carry a unitCode attribute naming its unit of measure.

EN 16931Fatal: the document is invalidLines and pricesCore fields

The short answer

BR-23 fails when the line quantity has no unitCode attribute, as in <cbc:InvoicedQuantity>2</cbc:InvoicedQuantity>. Add unitCode with the UN/ECE Recommendation 20 code for the unit the quantity is counted in, and use the same code on cac:Price/cbc:BaseQuantity if the line has one.

The attribute has to sit on the quantity element itself. A unitCodeListID without unitCode, or a unit mentioned only in the item name or description, does not count.

What the rule checks

For each cac:InvoiceLine or cac:CreditNoteLine, the rule passes when the line quantity element carries an attribute named unitCode. It checks that the attribute exists, not what it says.

An empty or blank attribute gets past this rule and is caught by others. When tried, unitCode="" and unitCode=" " each reported BR-CL-23, because neither is a recognised code, and PEPPOL-EN16931-R130, because neither matches the C62 on the base quantity. BR-23 itself was not reported.

A line with no quantity element at all fails here too, together with BR-22, because there is no element to carry the attribute.

The unit on cac:Price/cbc:BaseQuantity plays no part in this rule. When the unit was removed from both the quantity and the base quantity, only BR-23 was reported: the Peppol unit comparison runs only on a base quantity that has a unit.

TermMeaningUBL element
BT-130Invoiced quantity unit of measure codecac:InvoiceLine/cbc:InvoicedQuantity/@unitCode (cac:CreditNoteLine/cbc:CreditedQuantity/@unitCode in a credit note)
BT-129Invoiced quantitycac:InvoiceLine/cbc:InvoicedQuantity
BT-150Item price base quantity unit of measure codecac: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 source system stores quantities as plain numbers and has no unit field for the export to use.
  • The serialiser writes attributes only when a value is present, and the unit is null for service lines or manually entered lines.
  • The unit is sent in unitCodeListID, or only in the item description, and the unitCode attribute is left out.
  • A credit note mapper builds cbc:CreditedQuantity from scratch and copies the number without the attribute.

How to fix it

  1. Find the line from the finding location, then find the unit of its quantity in the source: the sales unit of the product, or the unit the service is charged in.
  2. Map that unit to its UN/ECE Recommendation 20 code, for example C62 for one, H87 for piece, HUR for hour or KGM for kilogram, and write it in upper case to unitCode on cbc:InvoicedQuantity or cbc:CreditedQuantity.
  3. Write the same code on cac:Price/cbc:BaseQuantity when the line has one. PEPPOL-EN16931-R130 rejects a base quantity whose unit differs from the quantity unit.
  4. Do not answer the Peppol finding by stripping the unit from the base quantity as well. That silences PEPPOL-EN16931-R130 and leaves BR-23 exactly where it was.

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 quantity is 2 with no unit, while the price is per 1 C62

<cac:InvoiceLine>
  <cbc:ID>1</cbc:ID>
  <cbc:InvoicedQuantity>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>

Fragment of the corrected invoice: the quantity and the price base quantity are both in C62

<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>

The only difference is unitCode="C62" on cbc:InvoicedQuantity, missing in the failing invoice and present in the corrected one. The failing document also reports PEPPOL-EN16931-R130 at cbc:BaseQuantity: the price base quantity says C62, and a quantity with no unit cannot match it. Adding the attribute to the quantity clears both.

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

  • Applies to cbc:InvoicedQuantity in a UBL Invoice and cbc:CreditedQuantity in a CreditNote. When tried on a credit note, removing the attribute from the credited quantity reported BR-23 and PEPPOL-EN16931-R130, the same pair as the invoice.
  • The UBL schema treats unitCode as optional, so its absence passes the XSD layer and is left to this rule.
  • Which code is acceptable is decided by BR-CL-23, not here. Once the attribute exists, a value such as EACH or pcs moves the finding to that rule.

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-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.