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:

  1. The CARF message schema (e.g., CARFMessage_v1.0.xsd) -- defines the overall message structure
  2. The STF types schema (e.g., isocarf_v1.0.xsd or stftypes_v4.xsd) -- defines common types like names, addresses, and TINs
  3. 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 PatternLikely CauseFix
"not a valid value of type 'xs:date'"Wrong date formatUse YYYY-MM-DD
"not a valid value of type 'xs:dateTime'"Wrong timestamp formatUse YYYY-MM-DDTHH:MM:SSZ
"value is not facet-valid"Value exceeds length or pattern constraintsCheck XSD restrictions (maxLength, pattern)
"element is not expected"Wrong element orderReorder elements to match XSD sequence
"namespace mismatch"Missing or wrong xmlnsMatch 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.

Get Expert Help