Category: XML Templates Last Updated: 2026-02-12 Applies To: EU DAC8 / OECD CARF XML Schema
---
Overview
Before submitting a DAC8/CARF XML report to a tax authority, you must validate it against the official XSD (XML Schema Definition) published by the OECD or the relevant national authority. Validation catches structural errors, missing required fields, incorrect data types, and other issues that would cause the submission to be rejected.
This article covers the validation process step by step, the tools available, and how to interpret and fix common validation errors.
Why Validate Before Submitting
Tax authority submission portals perform their own schema validation. If your XML file fails validation, it will be rejected -- often with minimal error detail. Validating locally before submission allows you to:
- Catch and fix errors before they reach the tax authority
- Get detailed error messages that pinpoint exactly where the issue is
- Iterate quickly without consuming submission attempts (some portals have rate limits)
- Build validation into your automated pipeline for continuous quality assurance
Step 1: Obtain the Official XSD
The XSD schema files define the exact structure, data types, and constraints for DAC8/CARF XML files. You need:
- The CARF message schema (e.g.,
CARFMessage_v1.0.xsd) -- defines the overall message structure - The STF types schema (e.g.,
isocarf_v1.0.xsdorstftypes_v4.xsd) -- defines common types like names, addresses, and TINs - Any jurisdiction-specific extensions your tax authority may require
These are typically published by the OECD on their Automatic Exchange of Information portal or by your national tax authority. Save them in a known directory alongside your XML files.
Step 2: Choose a Validation Tool
Command-Line Tools
xmllint (libxml2):
Available on Linux/macOS (and Windows via WSL or standalone builds). Fast and reliable.
xmllint --schema CARFMessage_v1.0.xsd --noout your_report.xml
If validation passes, you will see: your_report.xml validates
If validation fails, you will see error messages with line numbers.
xmlstarlet:
Another command-line option with similar capabilities.
xmlstarlet val -e -s CARFMessage_v1.0.xsd your_report.xml
Programming Language Libraries
Python (lxml):
from lxml import etree
schema_doc = etree.parse("CARFMessage_v1.0.xsd")
schema = etree.XMLSchema(schema_doc)
xml_doc = etree.parse("your_report.xml")
if schema.validate(xml_doc):
print("Validation passed")
else:
for error in schema.error_log:
print(f"Line {error.line}: {error.message}")
Java (javax.xml.validation):
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(new File("CARFMessage_v1.0.xsd"));
Validator validator = schema.newValidator();
try {
validator.validate(new StreamSource(new File("your_report.xml")));
System.out.println("Validation passed");
} catch (SAXException e) {
System.out.println("Validation failed: " + e.getMessage());
}
C# (.NET):
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add(null, "CARFMessage_v1.0.xsd");
XDocument doc = XDocument.Load("your_report.xml");
doc.Validate(schemas, (sender, args) => {
Console.WriteLine($"Validation error: {args.Message}");
});
GUI Tools
For manual validation during development:
- Oxygen XML Editor -- comprehensive XML development environment with built-in validation
- XMLSpy -- another professional XML editor with schema validation
- VS Code with XML extension -- free option with basic schema validation support
Step 3: Interpret Validation Errors
Common error types and what they mean:
Element Not Expected
Element '{urn:oecd:ties:carfmessage:v1}WrongElement': This element is not expected.
Expected is ({urn:oecd:ties:carfmessage:v1}TransactionSummary).
Cause: An XML element appears in the wrong position or has an incorrect name. Fix: Check the element name for typos and verify the correct order of child elements as defined in the XSD.
Missing Required Element
Element '{urn:oecd:ties:carfmessage:v1}AccountReport': Missing child element(s).
Expected is ({urn:oecd:ties:carfmessage:v1}DocRefId).
Cause: A required child element is missing.
Fix: Add the missing element. Check the XSD to see which elements are required (minOccurs="1").
Invalid Value for Type
Element '{urn:oecd:ties:carfmessage:v1}ReportingPeriod': '2025-01-01' is not a valid value
of the atomic type 'xs:date'.
Cause: The value does not match the expected data type or pattern.
Fix: Verify the format. Dates should be YYYY-MM-DD, currency codes should be 3 letters, country codes should be 2 letters, etc.
Namespace Mismatch
Element 'CARFMessage': No matching global declaration available for the validation root.
Cause: The root element's namespace does not match the XSD.
Fix: Ensure the xmlns declaration in your XML matches the target namespace defined in the XSD.
Attribute Errors
Element 'TIN': The attribute 'issuedBy' is required but missing.
Cause: A required attribute is not present on an element. Fix: Add the missing attribute. Check the XSD for required vs. optional attributes.
Step 4: Common Fixes
| Error Pattern | Likely Cause | Fix |
|---|---|---|
| "not a valid value of type 'xs:date'" | Wrong date format | Use YYYY-MM-DD |
| "not a valid value of type 'xs:dateTime'" | Wrong timestamp format | Use YYYY-MM-DDTHH:MM:SSZ |
| "value is not facet-valid" | Value exceeds length or pattern constraints | Check XSD restrictions (maxLength, pattern) |
| "element is not expected" | Wrong element order | Reorder elements to match XSD sequence |
| "namespace mismatch" | Missing or wrong xmlns | Match namespaces exactly from XSD |
Step 5: Integrate Validation into Your Pipeline
For production systems, validation should be automated:
import sys
from lxml import etree
def validate_dac8_xml(xml_path, xsd_path):
schema = etree.XMLSchema(etree.parse(xsd_path))
xml_doc = etree.parse(xml_path)
if schema.validate(xml_doc):
return True, []
errors = []
for error in schema.error_log:
errors.append({
"line": error.line,
"column": error.column,
"message": error.message,
"level": error.level_name
})
return False, errors
# Run validation
is_valid, errors = validate_dac8_xml("report_FR_2025.xml", "CARFMessage_v1.0.xsd")
if not is_valid:
for err in errors:
print(f"[{err['level']}] Line {err['line']}: {err['message']}")
sys.exit(1)
Run this as part of your report generation pipeline, after XML generation but before submission. Log all validation results and never submit a file that fails validation.
Additional Checks Beyond XSD Validation
XSD validation catches structural issues but not logical errors. You should also verify:
- DocRefId uniqueness across all messages you have ever submitted
- MessageRefId uniqueness across all messages
- Currency code validity (not all 3-letter strings are valid ISO 4217 codes)
- TIN format plausibility for the declared jurisdiction
- Aggregate value consistency (do the numbers add up correctly?)
- Correct receiving jurisdiction (do all users in the file match the ReceivingCountry?)
These business-logic checks require custom validation code beyond what XSD can provide.
Need help with DAC8 reporting?
Our team handles XML generation, TIN validation, and submission for CASPs across all 27 EU Member States.