ANAF e-Factura Error Codes: Complete Reference (2026)
Comprehensive reference for all ANAF e-Factura error codes. Covers BR-RO business rules, EN 16931 validation errors, XML schema violations, OAuth2 authentication errors, and rate limiting — with fixes for each.
Understanding ANAF Error Responses
When ANAF rejects an e-Factura invoice, the error response is returned as an XML document in Romanian. The response contains one or more error entries, each referencing a specific validation rule that failed. Understanding these errors -- and knowing how to fix them -- is the difference between a working integration and days of debugging.
ANAF errors fall into five categories: Romania-specific business rules (BR-RO), European base rules (BR, BR-CO, BR-CL), tax category rules (BR-S, BR-Z, BR-E, BR-AE, BR-IC, BR-O, BR-IG, BR-IP), XML schema validation errors, and HTTP-level errors (authentication, rate limiting). This guide covers all of them.
A typical ANAF error response looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<header xmlns="mfp:anaf:dgti:efactura:mesajErworiFact:v1"
dateResponse="202602101430"
ExecutionStatus="0"
index_incarcare="5024331779">
<Errors errorMessage="[BR-RO-010]-Numarul de inregistrare in Registrul Comertului
(BT-30) trebuie sa fie furnizat" />
</header>
The ExecutionStatus="0" indicates rejection. The errorMessage attribute contains
the rule code (BR-RO-010) and a Romanian-language description. You may receive multiple Errors
elements if several rules fail simultaneously.
Romania-Specific Rules (BR-RO)
These are rules added by Romania's CIUS-RO profile on top of the European EN 16931 standard. They enforce Romanian fiscal and regulatory requirements. Failing these rules is the most common cause of rejection for developers new to e-Factura.
| Rule | Error (translated) | Cause | Fix |
|---|---|---|---|
BR-RO-010 | Trade register number (BT-30) must be provided | The supplier's PartyLegalEntity/CompanyID is missing or empty. | Add the trade register number in J{county}/{number}/{year} format (e.g., J40/1234/2020) to the AccountingSupplierParty/Party/PartyLegalEntity/CompanyID element. |
BR-RO-011 | Trade register number format is invalid | The CompanyID exists but does not match the expected Romanian format. | Ensure the format is J{XX}/{NNNN}/{YYYY} where XX is the county code (01-52 or 40 for Bucharest), NNNN is the registration number, and YYYY is the year. Also accepted: F{XX}/{NNNN}/{YYYY} for sole traders. |
BR-RO-020 | Supplier city name (BT-37) is required | The supplier's postal address is missing the CityName element. | Add the CityName element within AccountingSupplierParty/Party/PostalAddress. |
BR-RO-021 | Supplier country subdivision (BT-39) is required | Romanian suppliers must include the county code in their address. | Add CountrySubentity with the Romanian county name (e.g., "RO-B" for Bucharest, "RO-CJ" for Cluj) to the supplier's postal address. |
BR-RO-030 | Customer city name (BT-52) is required for domestic | For B2B invoices where the customer is Romanian, the city is mandatory. | Add CityName to the AccountingCustomerParty/Party/PostalAddress. |
BR-RO-040 | Supplier VAT number must start with RO | The supplier's CompanyID in PartyTaxScheme does not start with "RO". | Ensure the VAT number includes the country prefix: RO12345678, not just 12345678. |
BR-RO-050 | Payment means code is required | The PaymentMeans/PaymentMeansCode element is missing. | Add a PaymentMeans section with a valid UNCL 4461 code: 30 (bank transfer), 48 (bank card), 49 (direct debit), 1 (cash). Bank transfer (30) is most common for B2B. |
BR-RO-060 | Supplier bank account (BT-84) required for bank transfer | Payment means is set to bank transfer (code 30) but no bank account is provided. | Add PayeeFinancialAccount/ID with the IBAN. Example: RO49AAAA1B31007593840000. |
BR-RO-065 | CustomizationID must include CIUS-RO identifier | The CustomizationID element does not contain the CIUS-RO URN. | Set to exactly: urn:cen.eu:en16931:2017#compliant#urn:efactura.mfinante.ro:CIUS-RO:1.0.1 |
BR-RO-070 | Document currency should be RON for domestic transactions | A domestic B2B invoice (both parties Romanian) uses a currency other than RON. | Set DocumentCurrencyCode to RON. EUR is allowed for cross-border transactions or when explicitly agreed between parties (add a note in the invoice). |
BR-RO-080 | VAT rate must be a valid Romanian rate | An invoice line uses a VAT rate not recognized by Romanian tax law. | Use 19% (standard), 9% (reduced I), 5% (reduced II), or 0% (zero rate / exempt). Other rates are not valid for Romanian invoices. |
BR-RO-100 | Invoice type code is not supported | The InvoiceTypeCode value is not one of the codes supported by ANAF. | Use 380 (commercial invoice), 381 (credit note), or 389 (self-billed invoice). Other UNCL 1001 codes are not accepted. |
BR-RO-110 | Tax point date required when different from issue date | The TaxPointDate is missing when the tax event occurs on a date different from the invoice issue date. | Add the TaxPointDate element (BT-7) if the VAT becomes chargeable on a date other than the issue date. Otherwise omit it -- the issue date is assumed. |
European Base Rules (BR, BR-CO, BR-CL)
These rules come from the EN 16931 European standard and apply to all EU e-invoicing systems, not just Romania. They enforce fundamental invoice structure and calculation integrity.
Structural Rules (BR)
| Rule | Description | Fix |
|---|---|---|
BR-01 | An invoice shall have a specification identifier (CustomizationID). | Always include the CustomizationID element. For Romania, use the CIUS-RO URN. |
BR-02 | An invoice shall have an invoice number (ID). | Add a non-empty cbc:ID element. Must be unique per supplier per fiscal year. |
BR-03 | An invoice shall have an issue date. | Add cbc:IssueDate in YYYY-MM-DD format. |
BR-04 | An invoice shall have an invoice type code. | Add cbc:InvoiceTypeCode. Use 380 for standard invoices, 381 for credit notes. |
BR-05 | An invoice shall have a document currency code. | Add cbc:DocumentCurrencyCode using ISO 4217 (e.g., RON, EUR). |
BR-06 | An invoice shall have a supplier name. | Add RegistrationName under AccountingSupplierParty/Party/PartyLegalEntity. |
BR-07 | An invoice shall have a customer name. | Add RegistrationName under AccountingCustomerParty/Party/PartyLegalEntity. |
BR-08 | An invoice shall have a supplier postal address. | Add the PostalAddress section under the supplier's Party with at minimum the Country/IdentificationCode. |
BR-10 | An invoice shall have a customer postal address. | Add the PostalAddress section under the customer's Party. |
BR-13 | An invoice shall have at least one invoice line. | Add at least one InvoiceLine element with line-level details. |
BR-16 | An invoice shall have the amount due for payment (BT-115). | Add LegalMonetaryTotal/PayableAmount with the total amount due. |
BR-21 | Each invoice line shall have an invoice line identifier. | Add cbc:ID to every InvoiceLine. Sequential integers (1, 2, 3...) work fine. |
BR-24 | Each invoice line shall have an item name. | Add Item/Name element with a description of the goods or services. |
BR-26 | Each invoice line shall have a line net amount. | Add LineExtensionAmount element. Must equal quantity multiplied by price, minus allowances. |
Calculation Rules (BR-CO)
Calculation rules verify that the numbers in your invoice are internally consistent. These are the most frustrating errors because they often come from rounding issues.
| Rule | Description | Fix |
|---|---|---|
BR-CO-10 | Sum of invoice line net amounts shall equal the sum of all lines' net amounts. | Ensure LegalMonetaryTotal/LineExtensionAmount equals the sum of all InvoiceLine/LineExtensionAmount values. Use banker's rounding (round half to even) to 2 decimal places. |
BR-CO-11 | Sum of allowances at document level shall equal the sum of all document-level allowance amounts. | Verify LegalMonetaryTotal/AllowanceTotalAmount matches the sum of all AllowanceCharge elements where ChargeIndicator is false. |
BR-CO-13 | Invoice total amount without VAT shall equal line extension amount minus allowances plus charges. | Recalculate: TaxExclusiveAmount = LineExtensionAmount - AllowanceTotalAmount + ChargeTotalAmount. |
BR-CO-15 | Invoice total VAT amount shall equal the sum of all VAT category tax amounts. | This is the most common calculation error. Each TaxSubtotal/TaxAmount must equal its TaxableAmount * rate, and the total TaxAmount in TaxTotal must equal the sum of all subtotal tax amounts. Round each subtotal independently, then sum. |
BR-CO-16 | Amount due for payment = total with VAT minus prepaid amount. | Verify: PayableAmount = TaxInclusiveAmount - PrepaidAmount + PayableRoundingAmount. |
Rounding tip: ANAF uses banker's rounding (IEEE 754 round half to even) for all monetary calculations. This means 2.345 rounds to 2.34, but 2.355 rounds to 2.36. JavaScript's
Math.round()uses round half up, which will cause BR-CO-15 failures. UseNumber(value.toFixed(2))or a dedicated decimal library likedecimal.jsfor financial calculations.
Code List Rules (BR-CL)
| Rule | Description | Fix |
|---|---|---|
BR-CL-01 | Currency code shall be coded using ISO 4217. | Use valid ISO 4217 codes: RON, EUR, USD, etc. |
BR-CL-10 | Invoice type code shall be from UNCL 1001 subset. | Use a supported code: 380 (invoice), 381 (credit note), 383 (debit note), 389 (self-billed). |
BR-CL-14 | Country code shall be from ISO 3166-1 alpha-2. | Use standard two-letter country codes: RO, DE, IT, etc. |
BR-CL-17 | Payment means code shall be from UNCL 4461. | Common values: 10 (cash), 30 (credit transfer), 48 (bank card), 49 (direct debit), 58 (SEPA credit transfer). |
BR-CL-20 | Unit of measure code shall be from UN/ECE Recommendation 20. | Common codes: C62 (unit/piece), HUR (hour), DAY (day), MON (month), KGM (kilogram), LTR (litre). |
Tax Category Rules (BR-S, BR-Z, BR-E, BR-AE)
Each VAT category has its own set of validation rules. Using the wrong category code for a given tax rate, or omitting required fields for a specific category, triggers these errors.
Standard Rate (BR-S)
| Rule | Description | Fix |
|---|---|---|
BR-S-01 | A VAT breakdown with category code S shall have a non-zero tax rate. | When using category S, the Percent element must be present and greater than 0 (use 19, 9, or 5 for Romania). |
BR-S-08 | For each VAT category S, the tax amount shall equal the taxable amount multiplied by the rate. | Recalculate: TaxAmount = TaxableAmount * (Percent / 100), rounded to 2 decimal places using banker's rounding. |
BR-S-09 | The taxable amount in a S category shall equal the sum of line net amounts for that category. | Sum all InvoiceLine/LineExtensionAmount values that use category S with the same rate. This sum must equal the TaxSubtotal/TaxableAmount. |
Zero Rate (BR-Z)
| Rule | Description | Fix |
|---|---|---|
BR-Z-01 | A VAT breakdown with category Z shall have a rate of 0. | Set Percent to 0 (not 0.00) when using category code Z. |
BR-Z-05 | Category Z: tax amount shall be 0. | The TaxAmount in a zero-rated TaxSubtotal must be exactly 0.00. |
BR-Z-10 | A VAT exemption reason code or reason shall be provided for Z-rated items. | Add TaxExemptionReasonCode and/or TaxExemptionReason to the TaxCategory. For exports, use code vatex-eu-132 or the applicable VAT directive article. |
Exempt (BR-E)
| Rule | Description | Fix |
|---|---|---|
BR-E-01 | A VAT breakdown with category E shall have a rate of 0. | Exempt lines must have a Percent of 0 and use category code E. |
BR-E-05 | Category E: tax amount shall be 0. | Tax amount must be exactly 0.00 for exempt categories. |
BR-E-10 | A VAT exemption reason or reason code shall be provided. | Add the exemption reason with reference to the relevant VAT directive article (e.g., Art. 132 for medical, educational, financial services). |
Reverse Charge (BR-AE)
| Rule | Description | Fix |
|---|---|---|
BR-AE-01 | A VAT breakdown with category AE shall have a rate of 0. | Reverse charge lines use category AE with a rate of 0. |
BR-AE-05 | Category AE: tax amount shall be 0. | No VAT is charged on reverse charge invoices; the buyer accounts for VAT. |
BR-AE-10 | A VAT exemption reason or reason code shall be provided. | Add a reference to the VAT directive article (typically Art. 194, 196, or 199 depending on the scenario). |
XML Schema Validation Errors
These errors occur when your XML does not conform to the UBL 2.1 schema definition, before any business rule validation runs. They are typically caused by element ordering mistakes, missing namespace declarations, or invalid data types.
| Error Pattern | Cause | Fix |
|---|---|---|
cvc-complex-type.2.4.a: Invalid content was found starting with element 'cbc:...' | XML elements are in the wrong order. UBL requires strict element ordering. | Reorder elements according to the UBL 2.1 schema. The correct order for top-level Invoice elements is: CustomizationID, ProfileID, ID, IssueDate, DueDate, InvoiceTypeCode, Note, TaxPointDate, DocumentCurrencyCode, etc. |
cvc-complex-type.2.4.b: The content of element 'cac:...' is not complete | A required child element is missing from a complex element. | Check the UBL schema for required children. For example, TaxCategory requires both ID and TaxScheme children. |
cvc-datatype-valid.1.2.1: '' is not a valid value for 'decimal' | An empty or non-numeric value in a numeric field. | Ensure all amount and quantity fields contain valid decimal numbers. Use 0.00 instead of empty strings. |
cvc-pattern-valid: Value '...' is not facet-valid | A value does not match the required pattern (e.g., date format, currency code format). | Check the value against the expected format. Dates must be YYYY-MM-DD. Currency codes must be exactly 3 uppercase letters. |
Namespace mismatch | Elements are using the wrong XML namespace prefix. | Ensure correct namespace declarations: cbc: for basic components, cac: for aggregate components. The root Invoice element must use the UBL Invoice namespace. |
HTTP-Level Errors
These errors occur at the transport level, before ANAF even parses your XML.
| HTTP Status | Error | Cause | Fix |
|---|---|---|---|
401 Unauthorized | Missing or malformed Authorization header | The Authorization: Bearer {token} header is missing, malformed, or the token has been revoked. | Verify the header format. Ensure you are sending Bearer {access_token} (note the space after Bearer). |
403 Forbidden | Token expired or insufficient scope | The access token has expired (90-day lifetime) or does not have the e-Factura scope. | Refresh the access token using the refresh token. If the refresh token has also expired (365-day lifetime), the user must re-authorize with their USB certificate. Check that the original authorization included the e-factura scope. |
404 Not Found | Invalid VAT number in URL path | The VAT number in the upload URL does not match any registered entity in ANAF's database. | Verify the VAT number. Use the ANAF VIES check endpoint to confirm the VAT number is active. Remember to use the numeric part only (no "RO" prefix) in the URL path. |
429 Too Many Requests | Rate limit exceeded | ANAF enforces approximately 100 requests per minute per VAT number. | Implement exponential backoff. Start with a 60-second wait after a 429, then double on each subsequent 429. Queue submissions and pace them at no more than 1 request per second per VAT number. |
500 Internal Server Error | ANAF server error | ANAF's servers experienced an internal failure. These are transient. | Retry with exponential backoff (initial delay 5 seconds, max 5 retries). ANAF has periodic maintenance windows (usually Saturday nights Romanian time). If 500s persist, check anaf.ro for service announcements. |
503 Service Unavailable | ANAF system maintenance | Scheduled or emergency maintenance. The system is temporarily unavailable. | Wait and retry. ANAF typically announces maintenance on their portal. Queue invoices for later submission. |
ANAF Status Messages
When you poll for invoice status using the listaMesajeFactura endpoint, ANAF returns
status messages in Romanian. Here are the possible statuses and their meanings:
| ANAF Status | English Translation | Meaning | Action |
|---|---|---|---|
ok | Accepted | ANAF validated and registered the invoice. It is now visible to the recipient. | Download the signed response to get the official ANAF index number. Store this as the legal reference. |
nok | Rejected | ANAF validation failed. The invoice was not registered. | Download the error report using the descarcare endpoint. Parse the error codes and fix the issues. You can resubmit the corrected invoice (with the same or new invoice number). |
in prelucrare | Processing | ANAF received the invoice and is still validating it. | Continue polling. Processing typically takes 30 seconds to 5 minutes, but can take up to 24 hours during peak periods (end of month, tax filing deadlines). |
XML valid cu avertismente | Valid with warnings | The invoice passed validation but has non-critical issues. | The invoice is accepted and registered. Review the warnings and consider fixing them for future invoices, but no resubmission is needed. |
Debugging Tips
When you encounter errors during ANAF integration, follow this systematic approach:
- Validate locally first. Run your XML through Schematron validation before submitting to ANAF. This catches 90% of errors instantly, without the latency of an API round trip. Use the EN 16931 base rules and CIUS-RO rules from the official EU repository.
- Check element ordering. UBL 2.1 is extremely strict about element order. If your XML builder generates elements alphabetically or in insertion order, you will get schema errors. Reference the official UBL 2.1 XSD schema for the correct sequence.
- Verify calculations independently. Build a separate calculation verification function that takes your invoice data and checks all BR-CO rules. This catches rounding errors before they reach ANAF.
- Test with minimal invoices. Start with the simplest possible invoice (one line item, standard 19% VAT rate, RON currency, bank transfer payment). Get this working first, then add complexity.
- Use the ANAF test environment. Always use
https://api.anaf.ro/test/FCTEL/restduring development. Test submissions are free and do not create real fiscal obligations. - Log full request/response cycles. When debugging, log the complete HTTP request (headers, body) and response. ANAF's error messages sometimes differ between the HTTP status code implication and the actual XML error detail.
How Mandato Handles Errors
When you use Mandato's API, you never see raw ANAF error codes. Mandato translates every error into clear, actionable English with field-level pointers:
// Mandato validates before submission and returns structured errors
const result = await mandato.invoices.create({
country: "RO",
supplier: {
vatNumber: "RO12345678",
name: "Acme SRL",
// Missing: tradeRegister — would trigger BR-RO-010
},
customer: {
vatNumber: "RO87654321",
name: "Client SRL",
},
lines: [
{ description: "Consulting", quantity: 1, unitPrice: 1000, vatRate: 19 },
],
});
// Mandato response (400 Bad Request):
{
"error": "validation_failed",
"message": "Invoice validation failed with 2 errors",
"errors": [
{
"code": "BR-RO-010",
"field": "supplier.tradeRegister",
"message": "Supplier trade register number is required for Romanian invoices. Expected format: J40/1234/2020",
"severity": "error"
},
{
"code": "BR-RO-020",
"field": "supplier.address.city",
"message": "Supplier city is required for Romanian invoices.",
"severity": "error"
}
]
} Mandato validates against all EN 16931 and CIUS-RO rules before submitting to ANAF. This means you get instant feedback, in English, with the exact field that needs correction. You never have to parse Romanian error messages or debug XML schema issues.
If an error somehow passes our pre-validation and ANAF rejects the invoice (rare, but possible during ANAF system updates), the webhook notification includes the translated error details, so you can surface them in your application immediately.
For more context on how the ANAF system works end-to-end, see our complete ANAF e-Factura integration guide. For the broader European compliance landscape, see the EU e-invoicing timeline.
Skip the complexity. Use Mandato.
One API for all EU e-invoicing systems. Send JSON, we handle XML conversion, government authentication, submission, and status tracking. Start with our free sandbox in 5 minutes.
Free sandbox with 50 invoices/month. No credit card required.