# How to Import MT940 Bank Statements in ERPNext and Troubleshoot Parsing Errors

> Learn to import MT940 bank statements in ERPNext. Discover how ERPNext handles the import process and troubleshoot common parsing errors with clear debugging steps. Get started today.

- Repository: [Frappe/erpnext](https://github.com/frappe/erpnext)
- Tags: how-to-guide
- Published: 2026-05-20

---

**ERPNext imports MT940 bank statements by detecting the format via mandatory SWIFT tags, preprocessing statement numbers to fix 6-digit truncation issues, parsing with the mt940 library, converting to CSV, and running the generic Data Import engine—most errors stem from missing format flags or non-standard tags that can be debugged through the Bank Statement Import logs.**

The MT940 bank statement import process in ERPNext (frappe/erpnext) allows organizations to automatically import SWIFT MT940 format files into the accounting system using the **Bank Statement Import** doctype. This standardized workflow transforms raw MT940 text files into structured `Bank Transaction` records through a series of validation, preprocessing, and conversion steps. Understanding the underlying Python implementation in the ERPNext source code is essential for troubleshooting parsing errors when dealing with non-standard bank exports.

## How the MT940 Bank Statement Import Process Works in ERPNext

The import flow follows seven distinct stages orchestrated by [`erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py`](https://github.com/frappe/erpnext/blob/main/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py).

### 1. File Upload and Storage

Users attach a `.txt` file containing the MT940 data to a `Bank Statement Import` document. The system stores the file path in the `import_file` field during the validation phase. According to the source code at lines 74-76, the `validate` method ensures the file attachment exists before proceeding.

### 2. MT940 Format Detection

Before conversion, the helper function `is_mt940_format()` checks for mandatory MT940 tags including `:20:`, `:25:`, `:28C:`, and `:61:` (lines 36-40). This validation ensures the uploaded file conforms to SWIFT standards before processing begins.

### 3. Format Flag Verification

If the file contains valid MT940 tags but the `import_mt940_fromat` checkbox remains unchecked, ERPNext raises the error: *"MT940 file detected. Please enable 'Import MT940 Format' to proceed."* This safeguard prevents accidental processing of mixed file types (lines 55-57).

### 4. Statement Number Preprocessing

Some banks emit 6-digit (or longer) statement numbers in the `:28C:` tag, which the `mt940` Python library rejects because it expects 5 digits or fewer. The `preprocess_mt940_content()` function (lines 14-42) automatically trims excess digits to the last five while preserving optional sequence parts, preventing parsing failures.

### 5. MT940 Parsing

The system calls `mt940.parse()` on the preprocessed content (lines 58-63). Any exception during this stage bubbles up as *"Failed to parse MT940 format..."* with the specific library error message attached.

### 6. CSV Generation for Data Import

Each parsed transaction normalizes into rows with columns for **Date**, **Deposit**, **Withdrawal**, **Description**, **Reference Number**, **Bank Account**, and **Currency** (lines 68-99). The generated CSV saves to the File Manager and attaches back to the import document for the generic Data Import engine.

### 7. Background Import Execution

ERPNext's `start_import()` background job (lines 55-71) processes the CSV file to create individual `Bank Transaction` records linked to the appropriate bank accounts.

## Common MT940 Parsing Errors and Troubleshooting Fixes

When the MT940 bank statement import process fails, the error messages directly map to specific validation checks in the source code.

### "The uploaded file does not appear to be in valid MT940 format."

This error triggers when `is_mt940_format()` cannot locate the mandatory tags (`:20:`, `:25:`, `:28C:`, `:61:`). Verify the raw `.txt` file in a text editor to ensure these SWIFT tags exist and the file is not corrupted or password-protected.

### "MT940 file detected. Please enable 'Import MT940 Format' to proceed."

This indicates the file passed format detection but the `import_mt940_fromat` field on the **Bank Statement Import** document is unchecked. Enable this flag in the import form before retrying.

### "Failed to parse MT940 format. Error: ..."

The `mt940` library raised an exception, typically due to statement numbers exceeding 5 digits or unexpected custom tags. While `preprocess_mt940_content()` handles the digit length issue automatically, persistent errors require manual inspection for non-standard bank-specific tags. Contact the bank for a cleaner export or strip custom tags manually.

### "Parsed file is not in valid MT940 format or contains no transactions."

The parser succeeded but returned an empty transaction list. Ensure the file contains transaction lines with `:61:` tags, as some banks provide balance-only statements without transaction details.

### "Bank Account column missing"

The generated CSV requires a **Bank Account** column. The import wizard automatically injects this via `add_bank_account()`, but manual CSV edits must preserve this header.

## Debugging Techniques for Failed Imports

When standard error messages insufficiently explain failures, use these diagnostic approaches based on the ERPNext implementation.

- **Inspect Raw File Content** – Download the uploaded `.txt` file via the File Manager and locate the `:28C:` line to verify statement number formatting.

- **Review Import Logs** – Navigate to **Bank Statement Import → Download Import Log** to view server-side tracebacks and identify exactly where `convert_mt940_to_csv()` failed.

- **Enable Verbose Error Logging** – Temporarily modify the exception handler in [`bank_statement_import.py`](https://github.com/frappe/erpnext/blob/main/bank_statement_import.py) to add `frappe.log_error(e, "MT940 Parse")` for capturing full stack traces in the Error Log doctype.

- **Manual Conversion Testing** – Invoke the preprocessing function directly in a Python console to isolate parsing issues from the broader import workflow.

## Practical Code Examples for MT940 Import

### Client-Side Upload and Import Trigger

Use this JavaScript pattern to programmatically upload a statement and initiate the MT940 conversion.

```javascript
frappe.call({
    method: "erpnext.accounts.doctype.bank_statement_import.bank_statement_import.upload_bank_statement",
    args: { company: "My Company", bank_account: "1234-5678-90" },
    callback: function(r) {
        const docname = r.message.name;
        // Enable MT940 import flag
        frappe.db.set_value('Bank Statement Import', docname, 'import_mt940_fromat', 1);
        // Attach the .txt file (assume `filedata` is a File object)
        const fd = new FormData();
        fd.append('file', filedata);
        fd.append('docname', docname);
        frappe.upload.upload_file(fd, {
            doctype: 'Bank Statement Import',
            docname: docname,
            fieldname: 'import_file',
            callback: function() {
                // Convert to CSV & start background job
                frappe.call({
                    method: "erpnext.accounts.doctype.bank_statement_import.bank_statement_import.convert_mt940_to_csv",
                    args: { data_import: docname, mt940_file_path: filedata.file_url },
                    callback: function(res) {
                        // The CSV is now attached; kick off import
                        frappe.call('erpnext.accounts.doctype.bank_statement_import.bank_statement_import.form_start_import',
                                   { data_import: docname });
                    }
                });
            }
        });
    }
});

```

### Server-Side Conversion Logic

The `convert_mt940_to_csv` whitelisted method executes the core transformation.

```python
@frappe.whitelist()
def convert_mt940_to_csv(data_import: str, mt940_file_path: str):
    # Load file content

    _file_doc, content = get_file(mt940_file_path)

    # Verify MT940 tags

    if not is_mt940_format(content):
        frappe.throw(_("The uploaded file does not appear to be in valid MT940 format."))

    # Ensure user enabled the flag

    if not frappe.get_doc("Bank Statement Import", data_import).import_mt940_fromat:
        frappe.throw(_("MT940 file detected. Please enable 'Import MT940 Format' to proceed."))

    # Pre-process statement numbers (truncates >5-digit numbers)

    processed_content = preprocess_mt940_content(content)

    # Parse using the mt940 library

    transactions = mt940.parse(processed_content)

    # Build CSV and save to File Manager

    csv_buffer = io.StringIO()
    writer = csv.writer(csv_buffer)
    writer.writerow(["Date", "Deposit", "Withdrawal", "Description", 
                    "Reference Number", "Bank Account", "Currency"])
    for txn in transactions:
        writer.writerow([...])  # Transaction data mapping

    
    saved_file = save_file(
        f"{frappe.utils.now_datetime():%Y%m%d%H%M%S}_converted_mt940.csv",
        csv_buffer.getvalue().encode("utf-8"),
        "Bank Statement Import",
        data_import,
        is_private=True,
        df="import_file",
    )
    return saved_file.file_url

```

### Manual Preprocessing for Debugging

Test the statement number fix outside the import workflow.

```python
from erpnext.accounts.doctype.bank_statement_import.bank_statement_import import preprocess_mt940_content

with open("my_statement.txt") as f:
    raw = f.read()

clean = preprocess_mt940_content(raw)
print(clean[:500])   # Verify :28C: line has ≤5 digits

```

## Key Source Files in the ERPNext Repository

Understanding these files deepens debugging capabilities.

- **[`erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py`](https://github.com/frappe/erpnext/blob/main/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py)** – Contains the core implementation including `is_mt940_format()`, `preprocess_mt940_content()`, and `convert_mt940_to_csv()`.

- **[`bank_statement_import_log.py`](https://github.com/frappe/erpnext/blob/main/bank_statement_import_log.py)** – Stores per-row import logs accessible via the Download Import Log feature.

- **[`bank_statement_import_list.js`](https://github.com/frappe/erpnext/blob/main/bank_statement_import_list.js)** – Provides front-end UI actions for Convert MT940 and Download Log.

- **[`bank_statement_import_log_column_map.py`](https://github.com/frappe/erpnext/blob/main/bank_statement_import_log_column_map.py)** – Maps CSV columns to doctype fields when using custom import templates.

## Summary

- ERPNext detects MT940 files by validating the presence of SWIFT tags `:20:`, `:25:`, `:28C:`, and `:61:` before processing begins.
- The `import_mt940_fromat` flag must be enabled on the **Bank Statement Import** document to proceed with conversion.
- The `preprocess_mt940_content()` function automatically truncates statement numbers in `:28C:` tags to 5 digits to comply with the mt940 library requirements.
- Failed imports generate CSV files for manual inspection and detailed logs accessible via the import document's Download Import Log button.
- The process ultimately leverages ERPNext's standard Data Import engine to create `Bank Transaction` records from the converted CSV.

## Frequently Asked Questions

### Why does ERPNext require the "Import MT940 Format" checkbox when it already auto-detects the file type?

The `import_mt940_fromat` field acts as an explicit consent mechanism. While `is_mt940_format()` can identify MT940 files by their tag structure, the checkbox prevents accidental processing when users upload mixed-format files, ensuring intentional MT940 conversion before the system executes `convert_mt940_to_csv()`.

### How do I fix "Failed to parse MT940 format" errors caused by 6-digit statement numbers?

The ERPNext source code includes `preprocess_mt940_content()` in [`bank_statement_import.py`](https://github.com/frappe/erpnext/blob/main/bank_statement_import.py) (lines 14-42) which automatically truncates statement numbers in `:28C:` tags to the last 5 digits. If errors persist, manually inspect the file for non-standard tags or bank-specific proprietary extensions that the `mt940` library cannot parse.

### Where can I find detailed error logs when the Bank Statement Import fails?

Access detailed tracebacks through **Bank Statement Import → Download Import Log**. For deeper server-side debugging, check the Error Log doctype in the Frappe desk or temporarily add `frappe.log_error(e, "MT940 Parse")` to the exception handlers in [`bank_statement_import.py`](https://github.com/frappe/erpnext/blob/main/bank_statement_import.py).

### Can I import MT940 files with custom tag structures or extensions?

The standard implementation requires strict adherence to MT940 tag formats (`:20:`, `:25:`, `:28C:`, `:61:`). For non-standard bank exports, you must preprocess the file to remove proprietary tags or modify the `preprocess_mt940_content()` function in the ERPNext source code to handle your specific bank's variations before calling `mt940.parse()`.