ZATCA rejects invoices with terse error codes, and decoding them under deadline pressure is brutal. Here are the top seven we see in production, ordered by frequency, with a tested fix for each.
1. ENT_ICV-001 — Invoice Counter Value out of sequence
ICV must increase monotonically per device. The cause is almost always parallel issuance from two processes against the same EGS. Fix: serialize ICV assignment behind a single source of truth (a database sequence works).
2. ENT_PIH-002 — Previous Invoice Hash mismatch
The hash you submitted as the previous one doesn't match what ZATCA has on file. Cause: someone re-submitted an old invoice or the local cache fell behind. Fix: query Fatoora for the latest cleared hash and reseed your chain.
3. KSA-25 — Tax category code missing or invalid
Each line item needs a UNCL5305 category code: S, Z, E, O, or AE. Common slip: leaving it blank for zero-rated lines. Fix: explicitly emit Z (not omit it).
4. KSA-12 — Seller VAT number malformed
Saudi VAT registration numbers are 15 digits and start with 3, ending with the checksum. A common mistake is submitting the 10-digit Commercial Registration number instead. Fix: pull the VAT from the tax_registrations table by kind='VAT', not from the trade-license field.
5. CLOCK_DRIFT — IssueDateTime more than 30 seconds out of sync
Server clock skew. Fix: NTP sync to pool.ntp.org, every minute, on every host that issues invoices.
6. KSA-08 — Standard invoice missing buyer VAT
B2B invoices in KSA require the buyer's VAT number (TaxID). Simplified (B2C) invoices do not. Fix: branch on InvoiceTypeCode (388 = standard, 388 with subtype 02 = simplified) in your serializer.
7. KSA-19 — Tax amount inconsistent with line totals
Sum of line tax amounts ≠ TaxTotal. Cause is almost always rounding mid-calculation. Fix: round only the final per-rate subtotal (banker's rounding), never per-line.