Quaterio

EN 16931 Validation Errors, Decoded: What BR-CO-15 and Friends Actually Mean

EN 16931 error messages are written for the people who wrote the standard. Here's what the most common ones mean in plain language, and what to change to fix them.

·6 minutes reading
Cover Image for EN 16931 Validation Errors, Decoded: What BR-CO-15 and Friends Actually Mean

The Error Message Problem

Here's a real validation error, in full, exactly as a real tool reports it:

[BR-CO-15]-Invoice total amount with VAT (BT-112) = Invoice total amount without VAT (BT-109) + Invoice total VAT amount (BT-110).

Now picture the person who receives it. They're in accounts receivable, it's four in the afternoon, an invoice bounced back from a customer, and this is what they've been given to work with.

The message isn't wrong. It's the rule, stated precisely, in the vocabulary of the specification. It's also close to useless for fixing anything, because it names three field codes, doesn't say which one is wrong, and doesn't say what to do.

This is the part of e-invoicing nobody budgeted for. The formats are documented, the rules are published as machine readable Schematron, and the errors are written by and for the people who wrote the standard.

Here's the translation layer.

First, How to Read a Rule ID

The prefix tells you what kind of rule you've hit, which usually tells you where to look.

PrefixMeaningTypical cause
BR-Business rule: something required is missingA field your invoice doesn't fill in
BR-CO-Co-occurrence: fields that must agreeArithmetic, or two fields that must both be present
BR-CL-Code list: a value must come from a fixed setA country, currency or unit code that isn't on the list
BR-DEC-Decimals: a number has too many decimal placesMore than two decimals on an amount
BR-S-, BR-Z-, BR-E-, BR-AE-, BR-G-, BR-O-VAT category rulesThe VAT treatment on a line doesn't match the invoice level breakdown

BT- numbers are business terms: the individual fields. BG- numbers are business groups: collections of fields, like a line item or a payment instruction.

Once you can read the prefix, most errors sort themselves into "a field is missing", "two numbers disagree" or "this VAT category has conditions you haven't met".

The Ones You'll Actually Hit

BR-CO-15: the totals don't add up

What it means: your gross total doesn't equal the net total plus the VAT total.

What usually causes it: rounding, per line, that accumulates. You calculate VAT on each line, round each one to two decimals, sum them, and the result is a cent away from VAT calculated on the invoice total. Or a document level discount got applied to one total and not the other.

The fix: derive the totals from the lines in one place rather than calculating them independently in two. If you're rounding per line, the invoice level VAT total has to be the sum of the rounded line values, not a fresh calculation on the net total.

This is the single most common failure in e-invoicing and it's almost always a floating point problem underneath. Amounts should be fixed scale decimals from end to end. A JSON number is how 1234.5000000001 gets onto an invoice.

BR-16: an invoice needs at least one line

What it means: exactly what it says.

What usually causes it: a mapping bug where the line array came through empty, or an invoice built from a credit note flow that dropped the lines. Occasionally, someone trying to send a pure summary invoice, which EN 16931 does not allow.

BR-DEC-*: too many decimal places

What it means: an amount has more than two decimals.

What usually causes it: unrounded arithmetic reaching the XML. A quantity of 3 at a unit price of 33.333 gives you a line total your system happily writes as 99.999.

The fix: round amounts to two decimals when you write them, not when you display them. Note that unit prices are allowed more decimals than totals, so don't over correct.

BR-CL-*: a code isn't on the list

What it means: a country, currency, unit or VAT category code isn't a valid entry from the code list the standard points at.

What usually causes it: free text where a code belongs. EUR is a currency code, Euro is not. SE is a country, Sweden is not. Unit codes are the least intuitive: a plain count of things is C62, hours are HUR, kilograms are KGM.

BR-S-08 and the VAT category family

What it means: the VAT you charged on the lines doesn't reconcile with the VAT breakdown you declared for the invoice.

What usually causes it: an invoice mixing VAT rates where the breakdown only lists one, or a line marked standard rate (S) sitting under a breakdown entry marked exempt (E).

The fix: build the VAT breakdown by grouping the lines rather than writing it by hand. One breakdown entry per distinct combination of category and rate, with the taxable amount being the sum of the lines in that group.

BR-AE-* and reverse charge

What it means: you've marked something reverse charge and haven't met the conditions.

What usually causes it: reverse charge requires an exemption reason, and it requires that no VAT is charged on those lines. Cross border invoices get this wrong when the seller sets the category but leaves the rate at the domestic value instead of zero.

Why We Wrote 223 of These

When we built our Factur-X validator, the plan was to cover the rules people hit most and let the rest print the rule identifier.

We ended up writing a plain language explanation for every rule in the standard, all 223 of them, and there's a test that fails and names any rule that ever falls back to raw specification text.

The reason is the long tail is exactly where you get stuck. The common errors are the ones you learn once and never look up again. The rule you hit at four in the afternoon, on an invoice that has to go out today, is the obscure one, and that's precisely the one a "we covered the top twenty" approach abandons you on.

It was the boring part of the build and it's the part I'd defend hardest.

Checking Without Uploading Your Invoice

One practical note, because it changes how you can use a tool like this.

Our validator runs the EN 16931 rules in your browser. The official CEN Schematron is compiled and shipped to the page, and your file is read by the tab you're already sitting in. Nothing is posted anywhere.

That matters for this specific document type. An invoice carries your customer's name, your unit prices, your discounts and your payment terms. Validating a batch of them means handing over your price list and your customer list. Every other validator I could find takes an upload.

You can verify the claim rather than trust it: open devtools, watch the network tab, drop a file in.

The deeper checks do need a server, and they say so. ISO PDF/A-3 conformance, the XRechnung rule set and PEPPOL BIS run on our backend as a separate button you press per file, because those rule sets and the veraPDF engine can't reasonably run in a browser tab.

And a "clean" result never quietly means "not checked". If your invoice declares XRechnung and you haven't run the deeper check, the report says the result is incomplete rather than telling you it passed. Getting that distinction wrong is how a validator gives someone false confidence, which on a compliance document is worse than giving them nothing.

If you want the other direction, generating a Factur-X invoice through our API runs the finished XML through this same Schematron before assembling the PDF, and returns the findings instead of the file if anything fails. It won't hand you a document you'd have had to debug from a rule ID anyway.