XSD Validation Is Not Enough for pain.001
Passing XSD validation is the minimum bar, not the finish line. Discover the three validation layers that determine whether a bank actually accepts your pain.001 file.
The three validation layers
Every pain.001 file passes through three independent validation layers before a bank accepts it. Most developers only run the first one.
The three layers — only layer 1 is handled by standard XSD tools
Layer 1: XSD schema validation
→ Checks structure, types, element ordering, cardinality
→ Tools: xmllint, Java SAX, any XSD validator
Layer 2: Business rule validation
→ Checks CtrlSum, NbOfTxs, IBAN MOD97, BIC format
→ Not expressible in XSD — requires custom logic
Layer 3: Bank / profile validation
→ Checks CH.03 mandatory fields, UBS restrictions, SEPA subset
→ Defined per bank or payment network, not standardizedWhat each layer catches
Layer 1 (XSD) catches malformed XML: missing mandatory elements, wrong data types, elements in the wrong order. These errors are easy to detect and fix early.
Layer 2 (business rules) catches semantic errors: the control sum does not match the sum of transaction amounts, the transaction count is wrong, an IBAN fails the MOD97 checksum. These require field-level logic that XSD cannot express.
Layer 3 (bank profile) catches profile conformance failures: a field allowed by ISO is forbidden by CH.03, a required field for UBS is missing, a character outside the SWIFT Basic Latin set appears in a name field.
What falls through standard XSD validation
A surprising number of payment file errors are invisible to standard XSD validators. The most common:
Errors that pass XSD but cause bank rejection
1. CtrlSum mismatch due to floating-point accumulation
XSD sees: <CtrlSum>99.99</CtrlSum> — valid decimal
Bank sees: sum of 3 × 33.33 = 99.99000000001 internally
2. Invalid IBAN checksum
XSD sees: <IBAN>CH9300762011623852957</IBAN> — valid string pattern
Bank sees: MOD97 check fails
3. Forbidden EqvtAmt element
XSD (base): <EqvtAmt> is optional and allowed
CH.03 profile: <EqvtAmt> is explicitly forbidden
4. Unsupported characters in name fields
XSD sees: <Nm>Müller GmbH</Nm> — valid UTF-8 string
SWIFT network: ü is not in the Basic Latin character setThe cost of a late rejection
When a bank rejects a payment file, the rejection typically happens hours after submission — sometimes the next business day. The payment misses its value date. If it is a salary run or a supplier payment with a due date, the consequence is immediate: SLA breach, penalty interest, or a damaged supplier relationship.
The developer then receives a terse rejection code (AM09, FF01, RC01) and must diagnose the file without access to the bank's internal validation logs. This diagnostic cycle takes hours. Pre-validation eliminates most of these cycles.
Pre-validation covers all three layers
A proper pre-validation tool runs all three layers before the file leaves your system. It reports which profile the file is compatible with, which business rules fail, and what the exact error is — in human-readable terms.