we-promise/sure · error · Provider::YahooFinance::Error
Failed to fetch exchange rates: #{rates_response.error.messa
Error message
Failed to fetch exchange rates: #{rates_response.error.message} What it means
Provider::YahooFinance::Error raised inside fetch_exchange_rate when the delegated fetch_exchange_rates call (a 10-day window ending at the target date) returned a failed ProviderResponse. It re-raises the underlying error's message — the actual cause is whatever made the range fetch fail (rate limit, invalid pair, parse error).
Source
Thrown at app/models/provider/yahoo_finance.rb:146
if from == to
Rate.new(date: date, from: from, to: to, rate: 1.0)
else
cache_key = "exchange_rate_#{from}_#{to}_#{date}"
if cached_result = get_cached_result(cache_key)
cached_result
else
# For a single date, we'll fetch a range and find the closest match
end_date = date
start_date = date - 10.days # Extended range for better coverage
rates_response = fetch_exchange_rates(
from: from,
to: to,
start_date: start_date,
end_date: end_date
)
raise Error, "Failed to fetch exchange rates: #{rates_response.error.message}" unless rates_response.success?
rates = rates_response.data
if rates.length == 1
rates.first
else
# Find the exact date or the closest previous date
target_rate = rates.find { |r| r.date == date } ||
rates.select { |r| r.date <= date }.max_by(&:date)
raise Error, "No exchange rate found for #{from}/#{to} on or before #{date}" unless target_rate
cache_result(cache_key, target_rate)
target_rate
end
end
end
end
endView on GitHub (pinned to e69894adb9)
Solutions
- Inspect the tail of the message — it names the real failure ('No chart data found...', 'Invalid response format...', rate-limit text); fix that root cause
- For rate-limit messages, back off and retry; check provider.health_status which tracks Yahoo's rate_limited state with 30-min freshness
- For 'No chart data found', verify the pair on finance.yahoo.com and use an inverse or cross pair via USD
- Add caching/TTL for repeated single-date lookups to reduce call volume
Example fix
// before
rate = provider.fetch_exchange_rate(from: "EUR", to: "USD", date: Date.yesterday)
// after
begin
rate = provider.fetch_exchange_rate(from: "EUR", to: "USD", date: Date.yesterday)
rescue Provider::YahooFinance::Error => e
if provider.health_status == :rate_limited
RetryableSyncJob.perform_later(wait: 10.minutes)
else
Rails.logger.warn("Yahoo FX failed: #{e.message}")
rate = fallback_provider.fetch_exchange_rate(from: "EUR", to: "USD", date: Date.yesterday)
end
end Defensive patterns
Strategy: try-catch
Try / catch
begin
provider.fetch_exchange_rate(from:, to:, date:)
rescue Provider::YahooFinance::Error => e
# message wraps the real cause; branch on health state
if provider.health_status == :rate_limited
retry_later(wait: 30.minutes)
else
fallback_provider.fetch_exchange_rate(from:, to:, date:)
end
end Prevention
- Check provider.health_status before batches — it tracks Yahoo rate_limited/unavailable with TTLs
- Cache single-date FX results so repeated syncs don't re-trigger the 10-day window fetch
- Keep a secondary FX provider wired for resilience
When it happens
Trigger: fetch_exchange_rate(from:, to:, date:) on a cache miss triggers fetch_exchange_rates for a 10-day window; if that inner call hit Yahoo rate limiting (429), returned no chart data, or returned invalid JSON, this wrapper error carries that message.
Common situations: Burst of exchange-rate lookups during a multi-currency portfolio sync exhausting Yahoo's unofficial rate limit; exotic pairs Yahoo doesn't quote; Yahoo changing response shape so parsing fails.
Related errors
- Failed to fetch security prices: #{prices_response.error.mes
- API error (code: #{error_code}): #{error_message}
- No exchange rate found for #{from}/#{to} on or before #{date
- No chart data found for currency pair #{from}/#{to}
- No security info found for #{symbol}
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/2d9198d16164f0d7.
Report an issue: GitHub.