we-promise/sure · error · Import::MappingError
Row #{row_number}: Account '#{account_name}' is not mapped t
Error message
Row #{row_number}: Account '#{account_name}' is not mapped to an existing account. Please map this account in the import configuration. What it means
Raised as Import::MappingError by TransactionImport (app/models/transaction_import.rb:24) when a CSV row's account name resolves to no account: mappings.accounts.mappable_for(row.account) returns nil. Before raising, the code adds the same message to errors[:base] with the 1-based row number and the offending account name (or '(blank)'). This is the safety net for CSV imports where every row must be attributed to a real account before transactions can be created.
Source
Thrown at app/models/transaction_import.rb:24
new_transactions = []
updated_entries = []
claimed_entry_ids = Set.new # Track entries we've already claimed in this import
rows.each_with_index do |row, index|
mapped_account = if account
account
else
mappings.accounts.mappable_for(row.account)
end
# Guard against nil account - this happens when an account name in CSV is not mapped
if mapped_account.nil?
row_number = index + 1
account_name = row.account.presence || "(blank)"
error_message = "Row #{row_number}: Account '#{account_name}' is not mapped to an existing account. " \
"Please map this account in the import configuration."
errors.add(:base, error_message)
raise Import::MappingError, error_message
end
category = mappings.categories.mappable_for(row.category)
tags = row.tags_list.map { |tag| mappings.tags.mappable_for(tag) }.compact
# Use account's currency when no currency column was mapped in CSV, with family currency as fallback
effective_currency = currency_col_label.present? ? row.currency : (mapped_account.currency.presence || family.currency)
# Check for duplicate transactions using the adapter's deduplication logic
# Pass claimed_entry_ids to exclude entries we've already matched in this import
# This ensures identical rows within the CSV are all imported as separate transactions
adapter = Account::ProviderImportAdapter.new(mapped_account)
duplicate_entry = adapter.find_duplicate_transaction(
date: row.date_iso,
amount: row.signed_amount,
currency: effective_currency,
name: row.name,
exclude_entry_ids: claimed_entry_idsView on GitHub (pinned to e69894adb9)
Solutions
- Open the import configuration and map every account name present in the CSV to an existing account, then retry the import.
- Inspect the CSV around the reported row number and fix the account cell (typos, stray whitespace, wrong column mapped) — '(blank)' means the account cell is empty.
- Pre-flight the file: list distinct row.account values and confirm each one has a mapping before starting the import.
- If a mapping genuinely cannot exist, remove or correct those rows in the CSV; the import aborts atomically on the first unmapped row.
Example fix
// before
import.create_transactions! # aborts: "Row 12: Account 'Checking 1234' is not mapped..."
// after
import.csv_rows.each_with_index do |row, i|
next if import.mappings.accounts.mappable_for(row.account)
raise "Row #{i + 1}: map '#{row.account}' before importing"
end
import.create_transactions! Defensive patterns
Strategy: validation
Validate before calling
names = import.csv_rows.map(&:account).compact.uniq
unmapped = names.reject { |n| import.mappings.accounts.mappable_for(n) }
fail "Unmapped accounts: #{unmapped.join(', ')}" if unmapped.any? Type guard
row.account.present? && import.mappings.accounts.mappable_for(row.account).present?
Try / catch
begin import.create_transactions! rescue Import::MappingError => e # e.message already names the offending row + account; show import.errors[:base] flash.now[:alert] = e.message end
Prevention
- Run a pre-flight pass listing distinct CSV account names vs mappings before starting the import.
- After uploading a CSV, always complete the mapping step for every detected account name.
- Watch for '(blank)' in the message — it indicates an empty account cell or a wrongly mapped CSV column.
When it happens
Trigger: Creating/running a TransactionImport whose CSV contains an account name that has no mapping configured: a renamed bank account, casing or whitespace differences between the CSV and the mapping, a blank account column with no default mapping, or mappings that were edited after the CSV was uploaded.
Common situations: Bank export uses 'Checking ••1234' while the mapping table has 'Checking'; CSV column order changed so the account column reads empty; the import configuration screen was submitted without mapping all distinct account names from the file.
Related errors
- Invalid date format for '#{row.date}': #{e.message}
- invalid_response
- record_not_found
- validation_failed
- record_not_found
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/e09796915dbeecf9.
Report an issue: GitHub.