errorcalculationEN 16931

BR-CO-17:VAT category tax amount must equal taxable amount times rate

Fix: Step 1: For every cac:TaxTotal/cac:TaxSubtotal, read cbc:TaxableAmount (BT-116), cac:TaxCategory/cbc:Percent (BT-119), cbc:TaxAmount (BT-117). Step 2: Compute the expected TaxAmount as `round_half_up(TaxableAmount * Percent / 100, 2)`. Use Decimal arithmetic, not float — `Decimal(taxable) * Decimal(percent) / Decimal('100')` in Python with `ROUND_HALF_UP`. Step 3: Compare to the emitted TaxAmount. If different by exactly 0.01 it's a rounding-mode bug. If different by more, the TaxableAmount or rate is wrong. Step 4: Rewrite cbc:TaxAmount with the recomputed value, keeping the currencyID attribute and two-decimal formatting (`'{:.2f}'.format(value)`). Step 5: Recompute downstream totals: BT-110 (cbc:TaxAmount on cac:TaxTotal — sum of subtotal TaxAmount) and BT-112 (cbc:TaxInclusiveAmount). Step 6: Re-validate. BR-CO-17 should clear, and BR-CO-14 should also pass if the totals are recomputed correctly. Step 7: If the input data was wrong (rate cast as integer, taxable amount truncated), fix the source mapping — auto-fixing the symptom hides a recurring bug. Upload your invoice to fix this automatically.

BR-CO-17 fires when the VAT category tax amount (BT-117) on a TaxSubtotal does not equal the VAT category taxable amount (BT-116) multiplied by the VAT category rate (BT-119) divided by 100, rounded to two decimals. It's the single-category sibling of BR-CO-14 (sum of category tax amounts equals document VAT total) and one of the most common Peppol calculation failures.

Severity
Fatal
Rule set
EN 16931
Country
All EU
Fix type
AUTO-FIX
Confidence
96%

Engine Classification

BLOCKED: This is a tax calculation error. We cannot recalculate because country-specific rounding rules apply, and we don't know which value is wrong. Source system must recalculate using proper tax rules.

Confidence: 96% · Applied automatically in pipeline

What is BR-CO-17?

BR-CO-17 is a fatal validation rule defined in the EN 16931 specification. It validates the 100). (3) Currency precision drift — emitting four decimals on TaxableAmount and two on TaxAmount creates rounding errors. (4) Multi-rate invoices where one TaxSubtotal is correct and another is off by 0.01. (5) Wrong VAT rate cast (e.g. 19 vs. 19.00 vs. 0.19) by a templating engine. (6) Negative TaxableAmount on credit notes flipped sign on TaxAmount differently. element under TaxSubtotal: `xs:decimal(cbc:TaxAmount) = round((xs:decimal(cbc:TaxableAmount) * xs:decimal(cac:TaxCategory > Percent)) div 100 * 100) div 100`. Failures arise from: (1) Banker's rounding vs. half-up rounding mismatches — financial systems often use round-half-to-even, schematron uses round-half-up. (2) Floating-point accumulation when category amounts are computed by summing line-level VAT instead of (taxable_amount * rate in the UBL invoice XML.

When this rule fires, the invoice is rejected by Peppol access points and never reaches the buyer.

Target path: The schematron checks, for each cac:TaxTotal/cac:TaxSubtotal: `xs:decimal(cbc:TaxAmount) = round((xs:decimal(cbc:TaxableAmount) * xs:decimal(cac:TaxCategory/cbc:Percent)) div 100 * 100) div 100`. Failures arise from: (1) Banker's rounding vs. half-up rounding mismatches — financial systems often use round-half-to-even, schematron uses round-half-up. (2) Floating-point accumulation when category amounts are computed by summing line-level VAT instead of (taxable_amount * rate / 100). (3) Currency precision drift — emitting four decimals on TaxableAmount and two on TaxAmount creates rounding errors. (4) Multi-rate invoices where one TaxSubtotal is correct and another is off by 0.01. (5) Wrong VAT rate cast (e.g. 19 vs. 19.00 vs. 0.19) by a templating engine. (6) Negative TaxableAmount on credit notes flipped sign on TaxAmount differently.

Why This Error Matters

Invoice rejected. Incorrect tax calculation causes VAT reporting errors and potential penalties.

BR-CO-17 is a hard failure — the invoice must be corrected and re-sent before it can reach the recipient.

Invoice Navigator can automatically correct this error in your pipeline. The fix is applied with full audit evidence, so your compliance trail remains intact.

Validator Behavior

  • ·Causes invoice rejection
  • ·Error returned: BR-CO-17
  • ·Specification: EN 16931

How to Fix It

1.

Identify the issue in your invoice

A VAT Category Tax Amount (BT-117) doesn't equal the Taxable Amount (BT-116) multiplied by the Rate (BT-119). The tax calculation is mathematically wrong.

2.

Correct this in your invoicing software

A VAT Category Tax Amount (BT-117) doesn't equal the Taxable Amount (BT-116) multiplied by the Rate (BT-119). The tax calculation is mathematically wrong.

3.

Re-export and validate

Generate a new invoice export from your accounting system and re-validate to confirm BR-CO-17 is resolved.

Before / After

Failing XML
<cac:TaxTotal>
  <cbc:TaxAmount currencyID="EUR">190.01</cbc:TaxAmount>
  <cac:TaxSubtotal>
    <cbc:TaxableAmount currencyID="EUR">1000.00</cbc:TaxableAmount>
    <cbc:TaxAmount currencyID="EUR">190.01</cbc:TaxAmount>
    <cac:TaxCategory>
      <cbc:ID>S</cbc:ID>
      <cbc:Percent>19.00</cbc:Percent>
      <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
    </cac:TaxCategory>
  </cac:TaxSubtotal>
</cac:TaxTotal>
Corrected XML
<cac:TaxTotal>
  <cbc:TaxAmount currencyID="EUR">190.00</cbc:TaxAmount>
  <cac:TaxSubtotal>
    <cbc:TaxableAmount currencyID="EUR">1000.00</cbc:TaxableAmount>
    <cbc:TaxAmount currencyID="EUR">190.00</cbc:TaxAmount>
    <cac:TaxCategory>
      <cbc:ID>S</cbc:ID>
      <cbc:Percent>19.00</cbc:Percent>
      <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
    </cac:TaxCategory>
  </cac:TaxSubtotal>
</cac:TaxTotal>

Technical Reference

XPathThe schematron checks, for each cac:TaxTotal/cac:TaxSubtotal: `xs:decimal(cbc:TaxAmount) = round((xs:decimal(cbc:TaxableAmount) * xs:decimal(cac:TaxCategory/cbc:Percent)) div 100 * 100) div 100`. Failures arise from: (1) Banker's rounding vs. half-up rounding mismatches — financial systems often use round-half-to-even, schematron uses round-half-up. (2) Floating-point accumulation when category amounts are computed by summing line-level VAT instead of (taxable_amount * rate / 100). (3) Currency precision drift — emitting four decimals on TaxableAmount and two on TaxAmount creates rounding errors. (4) Multi-rate invoices where one TaxSubtotal is correct and another is off by 0.01. (5) Wrong VAT rate cast (e.g. 19 vs. 19.00 vs. 0.19) by a templating engine. (6) Negative TaxableAmount on credit notes flipped sign on TaxAmount differently.
SpecEN 16931
StrategyBLOCKED: This is a tax calculation error. We cannot recalculate because country-specific rounding rules apply, and we don't know which value is wrong. Source system must recalculate using proper tax rules.

Code Example

Expected TaxAmount = 1000.00 * 19 / 100 = 190.00 (round half-up to two decimals). The 'before' XML emits 190.01 — a rounding-mode drift from summing line-level tax amounts that each rounded up by 0.005. The 'after' recomputes from TaxableAmount * Percent / 100. The cac:TaxTotal/cbc:TaxAmount must also be updated to match (BR-CO-14 dependency).

Common Causes

  • ·The schematron checks, for each cac:TaxTotal/cac:TaxSubtotal: `xs:decimal(cbc:TaxAmount) = round((xs:decimal(cbc:TaxableAmount) * xs:decimal(cac:TaxCategory/cbc:Percent)) div 100 * 100) div 100`. Failures arise from: (1) Banker's rounding vs. half-up rounding mismatches — financial systems often use round-half-to-even, schematron uses round-half-up. (2) Floating-point accumulation when category amounts are computed by summing line-level VAT instead of (taxable_amount * rate / 100). (3) Currency precision drift — emitting four decimals on TaxableAmount and two on TaxAmount creates rounding errors. (4) Multi-rate invoices where one TaxSubtotal is correct and another is off by 0.01. (5) Wrong VAT rate cast (e.g. 19 vs. 19.00 vs. 0.19) by a templating engine. (6) Negative TaxableAmount on credit notes flipped sign on TaxAmount differently.

Seeing this in production? The API handles BR-CO-17 automatically. See the fix response →

Frequently Asked Questions

The VAT category tax amount on one of your TaxSubtotal blocks does not equal the taxable amount times the VAT rate, rounded to two decimals. The most common cause is a rounding-mode mismatch (banker's vs. half-up) or aggregating line-level VAT instead of computing from the category taxable amount.

Yes, with high confidence (0.96). We recompute the TaxAmount from cbc:TaxableAmount * cbc:Percent / 100 with deterministic round-half-up to two decimals, update the cac:TaxSubtotal, and recompute the parent cac:TaxTotal/cbc:TaxAmount and the LegalMonetaryTotal/TaxInclusiveAmount. The only case requiring manual review is when the rate or taxable amount itself looks wrong (e.g. 0.19 written instead of 19).

BR-CO-17 validates one category at a time: TaxAmount = TaxableAmount * Rate / 100. BR-CO-14 validates the document-level VAT total: cac:TaxTotal/cbc:TaxAmount (BT-110) = sum of category TaxAmount (BT-117). A single off-by-one in BR-CO-17 often cascades into BR-CO-14. Fix BR-CO-17 first.

Round half up (commercial rounding) at the category level. The schematron uses XPath `round((TaxableAmount * Percent) div 100 * 100) div 100`, which is half-up. Avoid banker's rounding (round-half-to-even) — it's the default in many languages (Python's `round`, Java's BigDecimal HALF_EVEN) and causes 0.01 drift on amounts ending in 5.

Related Errors

Related Content

Last updated: 15 June 2026

Share this guide:

Validate your invoice

Drop your XML here to check for BR-CO-17

Auto-fix BR-CO-17 in seconds

Upload your invoice and we fix this error automatically. Financial fields are never touched.