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_ids

View on GitHub (pinned to e69894adb9)

Solutions

  1. Open the import configuration and map every account name present in the CSV to an existing account, then retry the import.
  2. 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.
  3. Pre-flight the file: list distinct row.account values and confirm each one has a mapping before starting the import.
  4. 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

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


AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21). Data as JSON: /api/errors/e09796915dbeecf9. Report an issue: GitHub.