Validation & Errors 7 min readPublished

XRechnung Rounding Errors: Why One Cent Gets an Invoice Rejected

XRechnung rounding errors explained: the BT-131 to BT-115 total chain, a three-line worked example with nine tested variants, and fixes for ERP and code.

docutools.pro Editorial TeamEditorial Team

Key takeaways

  • BR-CO-10, BR-CO-13, BR-CO-14 and BR-CO-15 test exact equality: a difference of EUR 0.01 is a fatal error.
  • Only the VAT amount per rate (BT-117) has a tolerance: BR-CO-17 and BR-S-09 accept a difference of less than 1.00.
  • The most common cause is summing unrounded line amounts instead of the rounded BT-131 values written to the file.
  • No KoSIT rule checks that quantity times price equals the line amount, so a wrong line total can still pass.
On this page

XRechnung rounding errors occur when a total in the XML does not exactly equal the amounts it is built from. The EN 16931 business rules BR-CO-10, BR-CO-13, BR-CO-14 and BR-CO-15 compare to the cent. A difference of EUR 0.01 is a "fatal" finding, and the KoSIT validator then recommends "reject" for the German XRechnung 3.0.2.

This guide is for finance, ERP and development teams that send XRechnung invoices to German public authorities or business customers. It works through one three-line invoice, shows which rounding choice triggers which rule, and gives you a fix you can apply at the source.

What does the error message look like?

Your validation report, or the XRechnung validator, shows one or more of these messages. The text is quoted from CEN Schematron 1.3.16, which the KoSIT configuration 2026-08-31 for XRechnung 3.0.2 bundles:

[BR-CO-10]-Sum of Invoice line net amount (BT-106) = Σ Invoice line net amount (BT-131).
[BR-CO-13]-Invoice total amount without VAT (BT-109) = Σ Invoice line net amount (BT-131) - Sum of allowances on document level (BT-107) + Sum of charges on document level (BT-108).
[BR-CO-14]-Invoice total VAT amount (BT-110) = Σ VAT category tax amount (BT-117).
[BR-CO-15]-Invoice total amount with VAT (BT-112) = Invoice total amount without VAT (BT-109) + Invoice total VAT amount (BT-110).

All four are "fatal". The German national rules (XRechnung Schematron 2.6.0) add no further calculation rules for standard invoices. Only the XRechnung Extension adds BR-DEX-09, which checks the amount due including third-party payments.

The total chain: which rule checks which amount?

Every total in an XRechnung depends on the one before it. If you know the chain, you can locate the break quickly:

StepBusiness termCalculationRuleTolerance
1BT-131 line net amountquantity × price, rounded to 2 decimalsBR-DEC-23 (decimals only)–
2BT-106 sum of linesΣ BT-131BR-CO-10none
3BT-109 total without VATBT-106 − BT-107 + BT-108BR-CO-13none
4BT-116 taxable amount per rateΣ BT-131 of that rate ± allowances/chargesBR-S-08less than 1.00
5BT-117 VAT per rateBT-116 × BT-119 / 100, roundedBR-CO-17, BR-S-09less than 1.00
6BT-110 total VATΣ BT-117BR-CO-14none
7BT-112 total with VATBT-109 + BT-110BR-CO-15none
8BT-115 amount dueBT-112 − BT-113 + BT-114BR-CO-16none

The tolerance column comes from the rule tests in the CEN Schematron, not from the rule descriptions. BR-CO-17 and BR-S-09 accept a stated tax amount greater than "calculated value minus 1" and less than "calculated value plus 1". BR-S-08 applies the same margin to the taxable amount. All other rules test for equality.

Two points in the table surprise many integration teams:

  • Step 1 is not validated. No rule in configuration 2026-08-31 recalculates BT-129 (quantity) × BT-146 (net price) against BT-131. Only the two-decimal limit is checked. The unit price BT-146 may carry more decimals.
  • BR-CO-16 is downgraded in the Extension. The "XRechnung Extension" scenario sets BR-CO-16 to "information" through customLevel and checks the amount due with BR-DEX-09 instead.

Worked example: three lines, nine variants

Muster GmbH invoices Beispiel AG for office supplies at the standard rate of 19 %:

LineItemQty (BT-129)Price (BT-146)ExactBT-131 rounded
1Copy paper A434.9914.9714.97
2Binders72.34516.41516.42
3Packing tape51.6258.1258.13

Calculated correctly: BT-106 = 39.52, BT-116 = 39.52, BT-117 = 39.52 × 0.19 = 7.5088, so 7.51, BT-110 = 7.51 and BT-112 = 47.03 (all EUR).

We built this invoice as an XRechnung 3.0 UBL file and ran nine variants through the validation engine of our viewer, which applies the rules of KoSIT configuration 2026-08-31. Results from 2 November 2026:

VariantWhat changedResult
Acorrect, as abovevalid, no findings
BBT-106 from unrounded lines: 14.97 + 16.415 + 8.125 = 39.51BR-CO-10 (fatal)
CVAT rounded per line: 2.84 + 3.12 + 1.54 = 7.50, used everywherevalid
DBT-117 = 7.50 (per line), BT-110 = 7.51 (from total)BR-CO-14 (fatal)
EBT-112 from rounded gross lines: 17.81 + 19.54 + 9.67 = 47.02BR-CO-15 (fatal)
Fline 2 with three decimals (16.415)BR-DEC-23, BR-DEC-09, BR-DEC-12, BR-DEC-19, BR-CO-10, UBL-DT-01
GBT-117 too high by 1.00 (8.51), totals adjustedBR-CO-17, BR-S-09 (fatal)
Hline 2 written as 16.41 instead of 16.42, totals consistentvalid
IBT-117 too high by 0.99 (8.50), totals adjustedvalid

What the test shows:

  1. One cent in BT-106, BT-110 or BT-112 is enough for a rejection (B, D, E).
  2. Both VAT methods pass (A and C), as long as the whole file uses one of them.
  3. "Valid" does not mean "correct". Variant H undercharges by one cent and variant I shows EUR 0.99 too much VAT. Both pass.

Variant I has tax consequences in Germany. Section 14(4) no. 8 of the German VAT Act (§ 14 UStG (opens in a new tab)) requires the invoice to state the tax amount on the consideration. Under § 14c(1) UStG (opens in a new tab), a supplier who shows a higher VAT amount than the law requires owes the excess as well. Validation does not replace a content check. How the German Ministry of Finance separates technical errors from content errors is covered in format error, business rule error or content error.

Why do rounding errors happen?

The causes, ordered by how often they appear in practice:

  1. Totals from unrounded values. The system keeps 16.415 and 8.125 internally, adds them up and rounds only the sum. BT-106 becomes 39.51, while the lines in the XML add up to 39.52 (variant B).
  2. Two VAT methods in one file. The VAT breakdown (BT-117) comes from a module that rounds per line, the header total (BT-110) from one that calculates on the base (variant D).
  3. Gross-price systems. Point-of-sale and webshop systems often work with gross prices and build BT-112 as the sum of gross lines. XRechnung requires BT-112 = BT-109 + BT-110 (variant E).
  4. Binary floating point. 16.415 is stored as 16.41499999… and rounds to 16.41. Python's round(8.125, 2) returns 8.12 because it rounds half to even. German commercial rounding expects 8.13.
  5. Document-level allowances. A 3 % discount on the total (BT-92) is rounded differently in BT-107 than in the per-rate breakdown, which triggers BR-CO-11 or BR-CO-13.
  6. Cash rounding without BT-114. If you round the amount due to the nearest 5 cents, the difference belongs in BT-114 (rounding amount). Otherwise BT-115 fails BR-CO-16.

How to find and fix the break

  1. Note the rule ID. BR-CO-10 points to BT-106, BR-CO-14 to BT-110 and BR-CO-15 to BT-112. The list of XRechnung error codes helps you map codes to fields. Take the meaning from the original rule text above.
  2. Recalculate the lines. Open the file in the XML viewer and list every cbc:LineExtensionAmount inside cac:InvoiceLine. Also check quantity × price yourself, because no validator does.
  3. Walk the chain top-down. BT-106 against Σ BT-131, then BT-109, BT-117 per rate, BT-110, BT-112 and BT-115. The first step that does not add up is the cause. Later findings are often follow-on errors.
  4. Identify the VAT method. Compare BT-117 with BT-116 × rate. A difference of a few cents means the system rounds per line, so BT-110 must show that same sum.
  5. Fix it in the source system. Change the rounding setting or the export mapping in the ERP. Patching the XML by hand fixes one invoice and leaves the next one broken.
  6. Export again and revalidate. Send the invoice only when no "fatal" finding remains.

For other errors around totals and mandatory fields, see the guide to fixing XRechnung validation errors.

How do you prevent rounding errors in code?

These rules in your invoicing logic prevent most cases:

RuleImplementation
Round every lineBT-131 = quantity × price, rounded half-up to 2 decimals
Build totals from rounded valuesBT-106 = sum of the rounded BT-131 values
One VAT method per invoiceeither VAT on BT-116 per rate, or the sum of line VAT, never both
Calculate net, derive grossalways BT-112 = BT-109 + BT-110
Decimal types, not floatsBigDecimal in Java, decimal in C#, Python decimal with ROUND_HALF_UP
Show cash rounding openlydifference in BT-114, then BT-115 = BT-112 − BT-113 + BT-114

A minimal Python version of steps 1 and 2:

from decimal import Decimal, ROUND_HALF_UP
CENT = Decimal("0.01")
lines = [("3", "4.99"), ("7", "2.345"), ("5", "1.625")]
bt131 = [(Decimal(q) * Decimal(p)).quantize(CENT, ROUND_HALF_UP) for q, p in lines]
bt106 = sum(bt131)                                          # 39.52
bt117 = (bt106 * Decimal("19") / 100).quantize(CENT, ROUND_HALF_UP)  # 7.51
bt112 = bt106 + bt117                                       # 47.03

Keep a test case like this one in your test suite permanently. Values with a 5 in the third decimal place (16.415 and 8.125) expose wrong rounding reliably. A full pre-send test plan is in test an e-invoice before sending, and running the same rules locally is covered in the KoSIT validator guide. More articles are collected under validation and errors.

How to check rounding with docutools.pro

  1. Open the XRechnung viewer and upload the XML file. The file is sent to our server for checking. The "KoSIT validation" checks the way the KoSIT validator does (configuration 2026-08-31) and lists rule IDs such as BR-CO-10 with the original rule text. The free plan includes 2 uploads per day up to 500 KB.
  2. The row "Sum of line items (BT-106)" under "Invoice items" adds up the line amounts from the file. Compare it with "Sum of line items" and "Net amount" in the "Extracted data" table, which show the totals as written in the XML. A one-cent gap stands out at once.
  3. For an invoice you are preparing yourself with a single VAT rate, click "Edit line items". On save, Smart Repair recomputes the chain from BT-106 to BT-115 from the lines and records the change as a note inside the XML. The free plan includes 1 Smart Repair per day; the Pro plan removes both limits.
  4. For new invoices, the XRechnung generator builds the totals from the lines you enter.

Sources

Last reviewed: November 2026

This article is general information, not tax or legal advice.

Tags:XRechnungKoSITEN 16931Validation

Tools for this article

Frequently asked questions

Is there a rounding tolerance in XRechnung?

Only for VAT per rate. In CEN Schematron 1.3.16, BR-CO-17 and BR-S-09 accept a VAT category tax amount (BT-117) that differs by less than 1.00 from the taxable amount times the rate, rounded. BR-S-08 uses the same margin for the taxable amount. Every other total rule, including BR-CO-10, BR-CO-14 and BR-CO-15, compares to the cent with no tolerance.

Should VAT be calculated per line or on the invoice total?

Either works technically. Calculating VAT on the taxable amount per rate is the method the rule text describes. Rounding VAT per line and adding it up usually lands within the BR-CO-17 tolerance too. What fails is mixing both: if BT-117 comes from line VAT but BT-110 from the total, BR-CO-14 rejects the invoice.

How many decimals are allowed in an XRechnung?

Two for every amount. The BR-DEC rules limit amounts such as BT-131, BT-106, BT-109, BT-110, BT-112, BT-116 and BT-117 to two decimals, and UBL-DT-01 applies the same limit to UBL amounts. The net price (BT-146) and the quantity (BT-129) have no such limit, so a unit price of 2.345 is allowed.

Why does Python round 8.125 to 8.12?

Because Python's built-in round uses round-half-to-even, and some decimal values such as 16.415 are stored as binary floats slightly below the written value. German commercial rounding expects 8.13 and 16.42. Use the decimal module with ROUND_HALF_UP, or an equivalent decimal type in your language, for every invoice amount.

Topic hubMore on Validation & ErrorsValidate e-invoices against the KoSIT rules and understand and fix validation errors, with concrete fixes rule by rule.