BR-KSA-F-04An amount or a quantity on this invoice is below zero

Mutabiq checks Saudi ZATCA Phase 2 e-invoice XML before you submit it: pre-validation against published ZATCA requirements, not an approval by the authority. This page explains one rule, BR-KSA-F-04.

Validate 5 invoices free

Five checks a month on the Free plan. The file is checked in memory and is never stored.

The message ZATCA prints

[BR-KSA-F-04]-All the document amounts and quantities must be positive, unless specified otherwise.

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.

An amount or a quantity on this invoice is below zero

Reported asnegativebelow zero

What is wrong

One of the amounts or quantities ZATCA's rule BR-KSA-F-04 selects holds a value below zero. The rule's printed message says that all the document amounts and quantities must be positive, and the check it actually runs asks whether the value is at least zero; it is the check that decides whether the document is accepted, and the difference between the two matters twice. Zero passes, because zero is not below zero - measured, an invoice whose line price is 0.00 comes back with no findings at all, and a negative zero passes as well - so this note is never about a nought written where you expected a figure. And an element that is present but empty is ignored altogether, because the check first requires the value to have at least one character in it. The words all the document amounts and quantities are also wider than the check: it selects twenty-one specific paths, each qualified by its parent, and three gaps in that list are worth knowing. The document-level allowance amount (BT-92) is not among them, although the document-level totals and the line-level and price-level allowance amounts are. A credit note's credited quantity is not among them, and neither is the base quantity at any level. And a cbc:PriceAmount that is not a direct child of cac:Price is not judged.

What to check in your ERP

A negative amount on an invoice nearly always means a credit was issued as an invoice: a return, a cancellation or a rebate exported with the invoice type code of a tax invoice and its figures negated. Issue it as a credit note instead, with type code 381, positive amounts, a billing reference to the invoice being corrected and the reason for issuing (KSA-10) filled in. The other regular causes are a discount written as a negative line rather than as an allowance - an allowance is cac:AllowanceCharge with a charge indicator of false and a positive amount - a prepayment or a rounding adjustment subtracted by negating an amount that has its own element, and a returned quantity negated on the line. Note that a negative document-level allowance amount is not judged by this rule but will be caught by the totals identities, so removing this note is not the same as making the document consistent.

An amount or a quantity on this invoice is not a number

Reported asnot_a_numbernot a number

What is wrong

One of the elements ZATCA's rule BR-KSA-F-04 selects holds text that is not a number. The check converts the text to a number and asks whether the result is at least zero; text that cannot be converted becomes not-a-number, which is not at least zero, so the rule is raised under the same code and the same printed message as a negative amount - the message will tell you the amounts must be positive even though the value is not a figure at all. What counts as convertible is narrow: an optional sign, digits, an optional full stop and nothing else. A grouping separator between the thousands, a currency code or symbol inside the value, a leading apostrophe left behind by a spreadsheet, a dash standing in for nought, brackets around a negative figure and a non-breaking space all fail it, the last because the only whitespace XML strips from the ends of a value is the ordinary space, the tab and the two line-break characters. An element that is present but completely empty is not this note - the check ignores it. A document in this state usually fails the schema check as well, because these elements are declared as decimal numbers.

What to check in your ERP

This is a serialisation problem rather than a tax one, so look at how the number is written and not at what it holds. The causes that produce it are a figure formatted for a human before it is exported (grouping separators, a currency symbol appended, brackets for a negative), a text field mapped into an amount element, a dash or the word nil written where a zero belongs, and a value pasted from a spreadsheet with its leading apostrophe still attached. Amounts and quantities must be written unformatted, with a full stop as the decimal separator, no grouping and no symbol; the currency belongs in the currencyID attribute on the element and nowhere else.

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

string-length(.) > 0 and not((.) >= 0)

Reported test

number(.) >= 0
Evaluated against
ubl:Invoice/cac:TaxTotal/cac:TaxSubtotal[normalize-space(cac:TaxCategory/cbc:ID)!='O']/cbc:TaxableAmount | ubl:Invoice/cac:AllowanceCharge/cbc:Amount | ubl:Invoice/cac:AllowanceCharge/cbc:BaseAmount | ubl:Invoice/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount | ubl:Invoice/cac:LegalMonetaryTotal/cbc:LineExtensionAmount | ubl:Invoice/cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount | ubl:Invoice/cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount | ubl:Invoice/cac:LegalMonetaryTotal/cbc:AllowanceTotalAmount | ubl:Invoice/cac:LegalMonetaryTotal/cbc:ChargeTotalAmount | ubl:Invoice/cac:LegalMonetaryTotal/cbc:PrepaidAmount | ubl:Invoice/cac:TaxTotal/cbc:TaxAmount | ubl:Invoice/cac:InvoiceLine/cac:AllowanceCharge/cbc:Amount | ubl:Invoice/cac:InvoiceLine/cac:AllowanceCharge/cbc:BaseAmount | ubl:Invoice/cac:InvoiceLine/cac:TaxTotal/cbc:TaxAmount | ubl:Invoice/cac:InvoiceLine/cac:Price/cbc:PriceAmount | ubl:Invoice/cac:InvoiceLine/cac:Price/cac:AllowanceCharge/cbc:Amount | ubl:Invoice/cac:InvoiceLine/cac:Price/cac:AllowanceCharge/cbc:BaseAmount | ubl:Invoice/cac:InvoiceLine/cbc:InvoicedQuantity | ubl:Invoice/cac:InvoiceLine/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount | ubl:Invoice/cac:InvoiceLine/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount | ubl:Invoice/cac:TaxExchangeRate/cbc:CalculationRate
Source
vendor/zatca/schematron/20210819_ZATCA_E-invoice_Validation_Rules.xsl:2909

As 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.

A worked example

A synthetic document from the measured test corpus that trips this rule, shown where it differs from one that passed. Mutabiq's report names the class of the value, never the value itself.

Where it differs from a document that passed

  • This example
  • A document that passed
  </cac:Item>  <cac:Price>This example:     <cbc:PriceAmount currencyID="SAR">-100.00</cbc:PriceAmount>A document that passed:     <cbc:PriceAmount currencyID="SAR">100.000</cbc:PriceAmount>  </cac:Price></cac:InvoiceLine>
Document
bad-75-negative-line-price.xml
Mutabiq's verdict
Not passed
Reported as
negativebelow zero

Download this example (.xml)Check it in Mutabiq

This page's example, checked by the same rules your own upload goes through. No upload and no sign-in.

Rules evaluated against the same part of the document. One wrong value often reports several of them at once.

Check an invoice

Check your own invoice

© 2026 Hayatiq AI Solutions F.Z.E. All rights reserved.