Skip to content

Ironfang Finance - Rule reference

BR-CO-20: Put a date in every line period, or leave the period out

A cac:InvoicePeriod on an invoice or credit note line must hold cbc:StartDate, cbc:EndDate or both. Unlike the document period, a code alone fails.

EN 16931Fatal: the document is invalidCore fieldsLines and prices

On this page

The short answer

BR-CO-20 fails when a cac:InvoicePeriod inside a line contains neither cbc:StartDate nor cbc:EndDate. Put the service dates of that line in it, or drop the element from lines that do not bill for a period.

The recorded example is the empty <cac:InvoicePeriod/> a template writes when both dates are null. Peppol rejects that element for being empty as well, under PEPPOL-EN16931-R008.

What the rule checks

The rule visits each line cac:InvoicePeriod, in cac:InvoiceLine or cac:CreditNoteLine, and passes when at least one of the two date elements is there. A start date alone or an end date alone is enough; when tried, each passed every layer.

Nothing else in a line period counts. When tried, a line period holding only cbc:DescriptionCode 35 reported BR-CO-20 with the warning UBL-CR-523, and one holding only a cbc:Description reported it with UBL-CR-524.

The line rule is stricter than the one for the whole document. When tried, a period holding only cbc:DescriptionCode 35 passed at document level, where BR-CO-19 accepts the code as a VAT point date code.

Whitespace does not make the element any less empty. When tried, an opening and a closing cac:InvoicePeriod tag on separate lines, with only whitespace between them, reported the same two rules as the recorded example.

Blank date elements never reach this rule: an empty cbc:StartDate or cbc:EndDate is not a valid date in the UBL schema, and when tried the XSD layer failed before any business rule ran.

TermMeaningUBL element
BG-26Invoice line periodcac:InvoiceLine/cac:InvoicePeriod (cac:CreditNoteLine/cac:InvoicePeriod in a credit note)
BT-134Invoice line period start datecac:InvoiceLine/cac:InvoicePeriod/cbc:StartDate (cac:CreditNoteLine/cac:InvoicePeriod/cbc:StartDate in a credit note)
BT-135Invoice line period end datecac:InvoiceLine/cac:InvoicePeriod/cbc:EndDate (cac:CreditNoteLine/cac:InvoicePeriod/cbc:EndDate in a credit note)

How an integration ends up here

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

  • The line template always writes cac:InvoicePeriod and fills the dates only for subscription or usage lines, so one-off items get an empty period.
  • The serialiser drops null date fields but keeps their parent element.
  • A billing period label such as a month name is written to cbc:Description on the line instead of being turned into dates.
  • The mapping for the document period, which may carry a VAT point date code, was reused for lines, where the code has no place.

How to fix it

  1. Find the line in the finding location, for example cac:InvoiceLine[1]/cac:InvoicePeriod[1].
  2. If the line bills a service period, write its first day to cbc:StartDate and its last day to cbc:EndDate as YYYY-MM-DD, or at least the one date the source holds.
  3. If the line is not tied to a period, remove cac:InvoicePeriod from it. The group is optional on a line.
  4. Emit the element only when one of its dates has a value, so that a null can never produce an empty group again.
  5. Keep period labels out of the line: cbc:Description and cbc:DescriptionCode are outside the model there and draw warnings.

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: line 1 has an empty period element

<cac:InvoiceLine>
  <cbc:ID>1</cbc:ID>
  <cbc:InvoicedQuantity unitCode="C62">2</cbc:InvoicedQuantity>
  <cbc:LineExtensionAmount currencyID="GBP">25.00</cbc:LineExtensionAmount>
  <cac:InvoicePeriod/>
  <!-- item and price omitted from this fragment -->
</cac:InvoiceLine>

Fragment of the corrected invoice: the line period runs from 1 to 15 August

<cac:InvoiceLine>
  <cbc:ID>1</cbc:ID>
  <cbc:InvoicedQuantity unitCode="C62">2</cbc:InvoicedQuantity>
  <cbc:LineExtensionAmount currencyID="GBP">25.00</cbc:LineExtensionAmount>
  <cac:InvoicePeriod>
    <cbc:StartDate>2026-08-01</cbc:StartDate>
    <cbc:EndDate>2026-08-15</cbc:EndDate>
  </cac:InvoicePeriod>
  <!-- item and price omitted from this fragment -->
</cac:InvoiceLine>

The failing invoice has an empty <cac:InvoicePeriod/> on line 1 where the corrected one has a start date of 2026-08-01 and an end date of 2026-08-15; the document period for August is the same in both. Beside BR-CO-20, the failing document reports PEPPOL-EN16931-R008 at the same element, because an element with no content is not allowed. Filling in the dates, or removing the element, 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 Invoice and CreditNote. When tried, an empty period on a cac:CreditNoteLine reported BR-CO-20 and PEPPOL-EN16931-R008 in the same way.
  • The period of the whole document is a matter for BR-CO-19: when tried, an empty cac:InvoicePeriod under the root reported that rule, not this one.
  • Once both dates are present, BR-30 checks their order, and against a document period PEPPOL-EN16931-R110 and PEPPOL-EN16931-R111 check that the line stays inside it.

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-28.1: source checked 2026-09-28, explanation last updated 2026-09-28.

The official definition of BR-CO-20 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.