CtrlSum Mismatch in pain.001
CtrlSum mismatches are among the most common pain.001 rejection causes. Learn what CtrlSum is, why it fails even when your math looks correct, and how to fix it.
What CtrlSum is
CtrlSum (Control Sum) is a mandatory field in the GrpHdr (Group Header) of every pain.001 file. It must equal the sum of all InstdAmt (Instructed Amount) values across all CdtTrfTxInf (Credit Transfer Transaction Information) blocks in the file.
Banks use CtrlSum as an integrity check. If the declared sum does not match the computed sum, the bank rejects the entire file — even if every individual transaction is perfectly valid.
CtrlSum must equal the sum of all InstdAmt values
<GrpHdr>
<NbOfTxs>3</NbOfTxs>
<CtrlSum>1500.00</CtrlSum> <!-- Must equal sum of all InstdAmt below -->
</GrpHdr>
<PmtInf>
<CdtTrfTxInf>
<InstdAmt Ccy="CHF">500.00</InstdAmt>
</CdtTrfTxInf>
<CdtTrfTxInf>
<InstdAmt Ccy="CHF">500.00</InstdAmt>
</CdtTrfTxInf>
<CdtTrfTxInf>
<InstdAmt Ccy="CHF">500.00</InstdAmt>
</CdtTrfTxInf>
</PmtInf>Where mismatches happen
Most CtrlSum mismatches come from one of three sources: floating-point arithmetic errors, incorrect nesting (summing only one PmtInf block instead of all), or copy-paste errors where the CtrlSum is not updated after adding or removing transactions.
The GrpHdr CtrlSum must cover all PmtInf blocks in the file. If a file has multiple PmtInf elements each containing transactions, the CtrlSum must be the total across every single transaction — not per PmtInf.
The floating-point precision trap
This is the most surprising cause of CtrlSum mismatches. Most payment amounts are currency values with 2 decimal places. Developers often accumulate them using floating-point addition in their code. Floating-point addition is not exact.
Floating-point accumulation produces invisible precision errors
// JavaScript / Python / most languages
3 * 33.33 === 99.99 // → false in many environments
// Actual result: 99.99000000000001
// This produces:
<CtrlSum>99.99</CtrlSum> <!-- Developer rounds and declares 99.99 -->
// But the bank recomputes: 33.33 + 33.33 + 33.33 = 99.99000000000001
// → AM09: ControlSum does not matchAlways accumulate monetary amounts as integers (minor currency units, e.g. cents) and convert to decimal only at serialization time.
Correct CtrlSum across multiple PmtInf blocks
When a file has multiple PmtInf blocks, CtrlSum must sum transactions from all of them.
Multiple PmtInf — CtrlSum covers all
<GrpHdr>
<NbOfTxs>4</NbOfTxs>
<CtrlSum>2000.00</CtrlSum> <!-- 1000 + 500 + 300 + 200 -->
</GrpHdr>
<PmtInf>
<!-- Batch 1 -->
<CdtTrfTxInf><InstdAmt Ccy="EUR">1000.00</InstdAmt></CdtTrfTxInf>
<CdtTrfTxInf><InstdAmt Ccy="EUR">500.00</InstdAmt></CdtTrfTxInf>
</PmtInf>
<PmtInf>
<!-- Batch 2 -->
<CdtTrfTxInf><InstdAmt Ccy="EUR">300.00</InstdAmt></CdtTrfTxInf>
<CdtTrfTxInf><InstdAmt Ccy="EUR">200.00</InstdAmt></CdtTrfTxInf>
</PmtInf>How to fix a CtrlSum mismatch
Step 1: Parse the file and extract all InstdAmt values as strings. Step 2: Convert each to an integer (multiply by 100 for 2-decimal currencies). Step 3: Sum the integers. Step 4: Divide by 100 and format with exactly 2 decimal places. Step 5: Update CtrlSum with this value.
Also verify that NbOfTxs equals the count of CdtTrfTxInf elements — they are usually wrong together.