we-promise/sure · warning

Invalid currency code '#{currency_value}' for <%= class_name

Error message

Invalid currency code '#{currency_value}' for <%= class_name %> account #{id}, defaulting to USD

What it means

This is a generator template (rails g provider ...) that emits a provider account model including the CurrencyNormalizable concern. During upsert_from_<provider>!, extract_currency calls parse_currency, which upcases/strips the provider value and requires both a strict 3-letter format (\A[A-Z]{3}\z) and recognition by the Money gem (Money::Currency.new). On failure, log_invalid_currency (the model's override that adds account context) warns and parse_currency returns nil, so the caller falls back to "USD" via extract_currency(data, fallback: "USD").

Source

Thrown at lib/generators/provider/family/templates/account_model.rb.tt:123

<% if investment_provider? -%>
      return unless <%= file_name %>_authorization_id.present?

      <%= class_name %>ConnectionCleanupJob.perform_later(
        <%= file_name %>_item_id: <%= file_name %>_item.id,
        authorization_id: <%= file_name %>_authorization_id,
        account_id: id
      )
<% else -%>
      <%= class_name %>ConnectionCleanupJob.perform_later(
        <%= file_name %>_item_id: <%= file_name %>_item.id,
        account_id: id
      )
<% end -%>
    end

    def log_invalid_currency(currency_value)
      Rails.logger.warn("Invalid currency code '#{currency_value}' for <%= class_name %> account #{id}, defaulting to USD")
    end
end

View on GitHub (pinned to e69894adb9)

Solutions

  1. Inspect the saved raw_payload for the account id in the log to see the exact currency value the provider sent
  2. If the code is a known provider convention, add a translation map in extract_currency (e.g. "GBX" => "GBP", "USDT" => "USD") before calling parse_currency, in both the generated model and the .tt template so regeneration keeps it
  3. If the provider genuinely omits currency for some account types, keep the USD fallback and accept the warning
  4. Feed back real-world codes into lib/generators/provider/family/templates/account_model.rb.tt so future generated providers map them

Example fix

# generated model - before
currency: extract_currency(data, fallback: "USD"),

# generated model - after (add mapping helper)
currency: extract_currency(data, fallback: "USD"),

# and inside the generated/private section:
def extract_currency(data, fallback:)
  raw = data[:currency].to_s.strip.upcase
  raw = { "GBX" => "GBP", "USDT" => "USD", "GBp" => "GBP" }.fetch(raw, raw)
  parse_currency(raw) || fallback
end
Defensive patterns

Strategy: validation

Validate before calling

# Pre-validate provider currency before upsert (generated model or processor)
KNOWN = { "GBX" => "GBP", "GBp" => "GBP", "USDT" => "USD" }
raw = data[:currency].to_s.strip.upcase
normalized = Money::Currency.new(KNOWN.fetch(raw, raw)) rescue nil
currency = normalized&.iso_code || "USD"

Type guard

# Ruby guard: true when the provider value maps to a real Money currency
def valid_provider_currency?(value)
  return false if value.blank?
  normalized = value.to_s.strip.upcase
  return false unless normalized.match?(/\A[A-Z]{3}\z/)

  Money::Currency.new(normalized)
  true
rescue Money::Currency::UnknownCurrencyError
  false
end

Prevention

When it happens

Trigger: Provider account payload whose currency field is not a valid ISO-4217 code recognized by the Money gem: "XXX" (3 letters but unknown to Money), nil/empty, symbols like "$", 4+ letter codes, or non-3-letter strings such as "pence" — anything failing app/models/concerns/currency_normalizable.rb:38 or :45.

Common situations: Brokerage aggregators returning non-ISO codes (GBX pence, USDT crypto codes), sandbox/test fixtures with placeholder currencies, providers sending display strings or localized currency names, provider API changes to the currency field format.

Related errors


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