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
Global (e.g. crypto) provider generator template. The generated account model includes CurrencyNormalizable and upsert_<provider>_snapshot! assigns currency: parse_currency(snapshot[:currency]) || "USD". parse_currency requires a 3-letter uppercase code recognized by the Money gem; when the snapshot's currency fails that check, the model's log_invalid_currency override emits this warning and the account silently persists with USD.
Source
Thrown at lib/generators/provider/global/templates/global_account_model.rb.tt:50
name: snapshot[:institution_name],
logo: snapshot[:institution_logo]
}.compact,
raw_payload: account_snapshot
)
end
def upsert_<%= file_name %>_transactions_snapshot!(transactions_snapshot)
assign_attributes(
raw_transactions_payload: transactions_snapshot
)
save!
end
private
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
- Check the account's raw_payload for the exact currency/symbol string the provider sent
- Add a symbol-to-ISO mapping in the generated upsert (e.g. "USDT" -> "USD", "WBTC" -> "BTC") before parse_currency, and mirror it in lib/generators/provider/global/templates/global_account_model.rb.tt
- For token-denominated balances that have no ISO code, decide an explicit conversion policy instead of relying on the silent USD default
- If snapshot[:currency] is nil, require the provider field or default intentionally rather than via the Money-gem miss
Example fix
# generated global account model - before
currency: parse_currency(snapshot[:currency]) || "USD",
# after
TOKEN_TO_ISO = { "USDT" => "USD", "USDC" => "USD", "WBTC" => "BTC" }.freeze
currency: parse_currency(TOKEN_TO_ISO.fetch(snapshot[:currency].to_s.strip.upcase, snapshot[:currency])) || "USD", Defensive patterns
Strategy: validation
Validate before calling
# Validate/translate crypto symbols before persisting the snapshot
TOKEN_TO_ISO = { "USDT" => "USD", "USDC" => "USD", "WBTC" => "BTC" }.freeze
raw = snapshot[:currency].to_s.strip.upcase
candidate = TOKEN_TO_ISO.fetch(raw, raw)
begin
currency = Money::Currency.new(candidate).iso_code
rescue Money::Currency::UnknownCurrencyError
currency = "USD" # or raise/report for token-denominated balances
end Type guard
def tradable_currency?(value) return false if value.blank? Money::Currency.new(value.to_s.strip.upcase) true rescue Money::Currency::UnknownCurrencyError false end
Prevention
- For global/crypto providers, maintain an explicit token-to-ISO mapping instead of relying on the silent USD default — wrong-currency balances distort valuations
- Log and alert when snapshot currency is nil separately from unknown-symbol cases; each needs a different fix
- Re-check stored accounts with currency 'USD' against raw_payload after enabling a mapping to repair past fallbacks
When it happens
Trigger: Crypto/global providers returning non-ISO asset symbols that the Money gem does not know: "USDT", "WBTC", "1INCH" (starts with a digit, fails \A[A-Z]{3}\z), symbols with hyphens, or nil currency fields — failing either the 3-letter regex or Money::Currency.new in app/models/concerns/currency_normalizable.rb.
Common situations: Wallet/exchange APIs whose balances are denominated in tokens rather than fiat codes; stablecoin or wrapped-asset symbols treated as invalid; new listings the Money gem has never heard of — for these the USD fallback produces wrong valuations, so mapping matters more than in the family template.
Related errors
- Invalid currency code '#{currency_value}' for <%= class_name
- Could not determine currency for #{symbol} from Tiingo searc
- <%= class_name %>Account::ActivitiesProcessor - Unmapped act
- Invalid institution URL for <%= class_name %> account #{prov
- Unexpected response format from search endpoint
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/2d2cd988460297bd.
Report an issue: GitHub.