What Mutabiq reports
One entry for each way this rule can be reported.
- Reported as
- What kind of value was found — empty, not_15_digits and the like — never the value itself.
Out-of-scope VAT breakdown states no taxable amount
Reported astaxable_amount_missingthe taxable amount is missing
What is wrong
A cac:TaxSubtotal directly under the invoice's own cac:TaxTotal is coded O - out of scope - under the VAT tax scheme and carries no cbc:TaxableAmount. EN 16931 rule BR-O-08, which ZATCA runs, compares that amount against the sum of the out-of-scope line amounts, plus out-of-scope charges, minus out-of-scope allowances. An absent element is an empty sequence in XPath: arithmetic over it yields the empty sequence and every comparison against it is false, so the rule fails on absence rather than passing over it, and the amount has to be written out even when it is nought. Two things about the sums, because they are narrower than the words suggest: they are taken from the direct children of the document root only, so an allowance attached to an invoice line is not in them; and the contributing lines, charges and allowances are picked up by the category letter alone, with no test that the tax scheme is VAT.
What to check in your ERP
The usual cause is an export that suppresses amount elements whose value is nought, and the out-of-scope group is the one it drops most often, because a breakdown rebuilt from posted tax lines has no tax line for a supply that was never taxed at all. Write cbc:TaxableAmount explicitly, formatted to two decimals and carrying the same currencyID attribute as the other amounts. If the group has elements but no figures, look at the per-category tax summary rather than at the export template. Expect the same suppression to be affecting your zero-rated and exempt breakdowns, so fix it once.
Out-of-scope VAT breakdown's taxable amount does not match its lines
Reported astaxable_amount_mismatchthe taxable amount does not match the lines
What is wrong
A cac:TaxSubtotal directly under the invoice's own cac:TaxTotal is coded O - out of scope - under the VAT tax scheme, and its cbc:TaxableAmount does not equal the sum of the out-of-scope line amounts, plus out-of-scope charges, minus out-of-scope allowances. EN 16931 rule BR-O-08, which ZATCA runs, compares the two exactly: there is no tolerance and no rounding step, unlike BR-S-09 and BR-CO-17, which allow a band of one currency unit around a category's VAT amount. A difference of one halalah fails this rule. Since SDK 3.4.8 the same check exists for the standard-rated, zero-rated and exempt groups too (BR-S-08, BR-Z-08 and BR-E-08), so every breakdown is tied to its own lines; the earlier release checked only the out-of-scope one. Two things about the sums, because they are narrower than the words suggest: they are taken from the direct children of the document root only, so an allowance attached to an invoice line is not in them; and the contributing lines, charges and allowances are picked up by the category letter alone, with no test that the tax scheme is VAT.
What to check in your ERP
Rebuild the figure by hand from the exported file: add up cbc:LineExtensionAmount on every line whose category is O, add the document-level charges coded O, subtract the document-level allowances coded O, and compare the result with the breakdown's cbc:TaxableAmount. The frequent causes are the out-of-scope taxable amount taken from the document's tax-exclusive total instead of from the out-of-scope group, a document-level allowance whose own cac:TaxCategory carries a different letter so the rule does not subtract it, a discount applied to the breakdown but not to the line's cbc:LineExtensionAmount, and rounding applied to the breakdown independently of the lines. Start at the per-category tax summary, which is where a breakdown and its lines stop agreeing.
Out-of-scope VAT breakdown with nothing out of scope on the invoice
Reported asout_of_scope_unusedan out-of-scope breakdown with nothing out of scope
What is wrong
The invoice's VAT breakdown has a cac:TaxSubtotal coded O - not subject to VAT - under the VAT scheme, but no line item and no document-level allowance or charge is coded O under the VAT scheme. BR-O-08 checks that the out-of-scope taxable amount equals the out-of-scope lines less allowances plus charges, and ZATCA's current checker reports a breakdown with nothing to add up. ZATCA flags this as a warning, which does not by itself reject the document.
What to check in your ERP
Either the breakdown should not be there, or the lines it summarises are coded with another category. Check that the category code on each line item (cac:ClassifiedTaxCategory/cbc:ID), and its tax scheme, match the breakdown the line is totalled into.
Out-of-scope breakdown was judged on a document with no invoice lines
Reported asno_invoice_lineno invoice lines to judge against
What is wrong
A cac:TaxSubtotal directly under the invoice's own cac:TaxTotal is coded O - out of scope - under the VAT tax scheme, and the document carries no cac:InvoiceLine anywhere in it. Only rule packs before 2.0.0 report this: SDK 3.0.8's BR-O-08 began by requiring at least one invoice line to exist, so with none the rule failed whatever the taxable amount said. In SDK 3.4.8, which rule pack 2.0.0 reads, BR-O-08 asks instead whether any line, allowance or charge uses the out-of-scope category (EN:1449-1450), as a warning, so a report produced under 2.0.0 never carries this note. The state is one a schema-valid invoice cannot reach in any case: UBL 2.1 requires at least one cac:InvoiceLine on an invoice, so the document fails the schema check and MTB-XSD-01 is the note that describes it.
What to check in your ERP
Read the schema note on the same report first, because it names the same defect from the standard's own side, then look at whether any lines were exported at all. A document with a full set of totals and no lines normally comes from an export that builds the header and the tax summary from one query and the lines from another: a filter on line type that excluded every line, a header-only adjustment raised without lines, or a run against a document whose lines were removed between the two reads. Confirm it by opening the exported file and searching it for cac:InvoiceLine.
The clause that runs
Quoted from the validation-rule stylesheet ZATCA publishes, at the file and line named below. The executed guard is what the check runs; the reported test is what it prints when it fails, and the two are not always the same.
Executed guard
count(/*/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory[normalize-space(cbc:ID) = 'O'][cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT'])> 0 and not(exists(../../../cac:AllowanceCharge/cac:TaxCategory[cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT']/cbc:ID[normalize-space(.) = 'O']) or exists(../../../cac:InvoiceLine[cac:Item/cac:ClassifiedTaxCategory[cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT']/cbc:ID[normalize-space(.) = 'O']])) or not((xs:decimal(../cbc:TaxableAmount) = (sum(../../../cac:InvoiceLine[cac:Item/cac:ClassifiedTaxCategory/normalize-space(cbc:ID)='O']/xs:decimal(cbc:LineExtensionAmount)) + sum(../../../cac:AllowanceCharge[cbc:ChargeIndicator=true()][cac:TaxCategory/normalize-space(cbc:ID)='O']/xs:decimal(cbc:Amount)) - sum(../../../cac:AllowanceCharge[cbc:ChargeIndicator=false()][cac:TaxCategory/normalize-space(cbc:ID)='O']/xs:decimal(cbc:Amount)))))
Reported test
count(/*/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory[normalize-space(cbc:ID) = 'O'][cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT'])> 0 and (exists(../../../cac:AllowanceCharge/cac:TaxCategory[cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT']/cbc:ID[normalize-space(.) = 'O']) or exists(../../../cac:InvoiceLine[cac:Item/cac:ClassifiedTaxCategory[cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT']/cbc:ID[normalize-space(.) = 'O']])) or (exists(//cac:InvoiceLine) and (xs:decimal(../cbc:TaxableAmount) = (sum(../../../cac:InvoiceLine[cac:Item/cac:ClassifiedTaxCategory/normalize-space(cbc:ID)='O']/xs:decimal(cbc:LineExtensionAmount)) + sum(../../../cac:AllowanceCharge[cbc:ChargeIndicator=true()][cac:TaxCategory/normalize-space(cbc:ID)='O']/xs:decimal(cbc:Amount)) - sum(../../../cac:AllowanceCharge[cbc:ChargeIndicator=false()][cac:TaxCategory/normalize-space(cbc:ID)='O']/xs:decimal(cbc:Amount))))) or (exists(//cac:CreditNoteLine) and (xs:decimal(../cbc:TaxableAmount) = (sum(../../../cac:CreditNoteLine[cac:Item/cac:ClassifiedTaxCategory/normalize-space(cbc:ID)='O']/xs:decimal(cbc:LineExtensionAmount)) + sum(../../../cac:AllowanceCharge[cbc:ChargeIndicator=true()][cac:TaxCategory/normalize-space(cbc:ID)='O']/xs:decimal(cbc:Amount)) - sum(../../../cac:AllowanceCharge[cbc:ChargeIndicator=false()][cac:TaxCategory/normalize-space(cbc:ID)='O']/xs:decimal(cbc:Amount)))))
- Evaluated against
/*/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory[normalize-space(cbc:ID) = 'O'][cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT']- Source
vendor/zatca/schematron/CEN-EN16931-UBL.xsl:1450As shipped in ZATCA SDK 3.4.8: the copy quoted here is, byte for byte, the file that release ships. The date in the file name is the name ZATCA gives the file; the rules in it are those of SDK 3.4.8.
© 2026 Hayatiq AI Solutions F.Z.E. All rights reserved.