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
  end

View on GitHub (pinned to e69894adb9)

Solutions

  1. 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
  2. For rate-limit messages, back off and retry; check provider.health_status which tracks Yahoo's rate_limited state with 30-min freshness
  3. For 'No chart data found', verify the pair on finance.yahoo.com and use an inverse or cross pair via USD
  4. 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

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


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