Skip to content

PEPPOL-EN16931-R008Remove empty elements from the document

An element has no text and no child elements. Peppol does not allow empty elements: leave out any optional element you have no value for.

Peppol BIS BillingFatal: the document is invalidCore fieldsXML input

The short answer

PEPPOL-EN16931-R008 fails once for every element that has no child elements and no text other than whitespace. The finding location is the path of the empty element. If the value is optional and you do not have it, remove the element; if it is required, supply the value.

In the recorded example the optional buyer accounting reference, cbc:AccountingCost, is written as an opening and closing tag with nothing between them. An optional element with no value should simply be absent.

What the rule checks

The rule has no condition of its own. It selects every element, at any depth and with any name, that has no child elements and whose text is empty after whitespace is stripped, and it reports each one.

All of these were reported when tried: an open and close tag with nothing between them, a self-closing tag, an element holding only spaces, tabs or line breaks, and an element holding only an XML comment.

Attributes do not count as content. An element with an attribute and no text is still empty.

Aggregates count too. A cac:PaymentTerms with no children is reported at that element. A parent whose children are all empty is not itself reported, but each empty child is, so a cac:Contact with three blank fields produces three findings.

A non-breaking space ( ) is not treated as whitespace, so an element containing only that character is not reported. That is a value made of one invisible character, not a fix.

TermMeaningUBL element
-Every element in the document, at any depth//*
BT-19Buyer accounting reference (the element in the recorded example)cbc:AccountingCost

How an integration ends up here

Possible causes, from the shape of the rule rather than from measured usage:

  • The serialiser writes every mapped field and turns null or empty strings into empty elements instead of skipping them.
  • A template has fixed optional elements such as cbc:Note, cbc:AccountingCost or the contact fields, and they are left blank when the source has nothing.
  • Values are trimmed after the decision to emit the element, so a field holding only spaces becomes an empty element.
  • A wrapper such as cac:Contact or cac:PaymentTerms is always emitted and its children are conditional, leaving an empty shell.

How to fix it

  1. Use the location in each finding to identify the element. There is one finding per empty element, so the list is complete.
  2. For an optional element with no value, do not emit it. Make the serialiser skip null, empty and whitespace-only values as a general rule, not field by field.
  3. After removing empty children, check the parent. If it now has no children, remove it too, or it becomes the next empty element reported.
  4. For an element that another rule requires, fix the source data so there is a real value. Do not fill it with a placeholder such as a dash or N/A unless that is what the business data says.

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 buyer accounting reference is present but empty

<cbc:DocumentCurrencyCode>GBP</cbc:DocumentCurrencyCode>
<cbc:AccountingCost></cbc:AccountingCost>
<cbc:BuyerReference>BUYER-REF-001</cbc:BuyerReference>

Fragment of the corrected invoice: the element carries a value. Leaving the element out altogether also passes

<cbc:DocumentCurrencyCode>GBP</cbc:DocumentCurrencyCode>
<cbc:AccountingCost>COST-123</cbc:AccountingCost>
<cbc:BuyerReference>BUYER-REF-001</cbc:BuyerReference>

Only cbc:AccountingCost differs: empty in the failing document, COST-123 in the corrected one. The failing document reports only PEPPOL-EN16931-R008. The UBL schema accepts an empty text element, and EN 16931 has no rule about this optional field, so the XSD and EN 16931 layers both pass.

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 UBL Invoice and CreditNote alike, and to every element in the document, including ones inside cac:InvoiceLine or cac:CreditNoteLine.
  • Some empty elements do not get this far. An empty amount or an empty date, for example, fails the XSD layer first; the EN 16931 and Peppol layers are then skipped, so this rule is not reported for them.
  • When a required element is empty, this rule arrives together with the rule that requires the value. An empty cbc:CustomizationID, for example, reports BR-01 and PEPPOL-EN16931-R004 as well.
  • An empty element is no way round a presence rule. An empty cbc:BuyerReference is enough for PEPPOL-EN16931-R003, which only looks for the element, but it is reported here.

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 PEPPOL-EN16931-R008 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.