we-promise/sure · error · Provider::YahooFinance::Error

Invalid response format: #{e.message}

Error message

Invalid response format: #{e.message}

What it means

Provider::YahooFinance::Error raised in fetch_exchange_rates when JSON.parse fails on the chart endpoint's response body. Yahoo returned something that is not valid JSON — typically an HTML error/bot-check page, an empty body, or a truncated response — so parsing raised JSON::ParserError, re-raised as a typed provider error.

Source

Thrown at app/models/provider/yahoo_finance.rb:188

      if from == to
        generate_same_currency_rates(from, to, start_date, end_date)
      else
        cache_key = "exchange_rates_#{from}_#{to}_#{start_date}_#{end_date}"
        if cached_result = get_cached_result(cache_key)
          cached_result
        else
          # Try both direct and inverse currency pairs
          rates = fetch_currency_pair_data(from, to, start_date, end_date) ||
                  fetch_inverse_currency_pair_data(from, to, start_date, end_date)

          raise Error, "No chart data found for currency pair #{from}/#{to}" unless rates&.any?

          cache_result(cache_key, rates)
          rates
        end
      end
    rescue JSON::ParserError => e
      raise Error, "Invalid response format: #{e.message}"
    end
  end

  # ================================
  #           Securities
  # ================================

  def search_securities(symbol, country_code: nil, exchange_operating_mic: nil)
    with_provider_response do
      cache_key = "search_#{symbol}_#{country_code}_#{exchange_operating_mic}"
      if cached_result = get_cached_result(cache_key)
        cached_result
      else
        throttle_request
        response = client.get("#{base_url}/v1/finance/search") do |req|
          req.params["q"] = symbol.strip.upcase
          req.params["quotesCount"] = 25
        end

View on GitHub (pinned to e69894adb9)

Solutions

  1. Log or inspect response.body when this fires — HTML content confirms a block/consent page rather than a parse bug
  2. Back off and retry later; check provider.health_status which tracks Yahoo's availability
  3. Route requests through a different egress IP or add a browser-like User-Agent if running from a datacenter
  4. Fall back to another rates provider; Yahoo's unofficial endpoints change without notice

Example fix

// before
rates = provider.fetch_exchange_rates(from: "EUR", to: "USD", start_date: s, end_date: e)

// after
begin
  rates = provider.fetch_exchange_rates(from: "EUR", to: "USD", start_date: s, end_date: e)
rescue Provider::YahooFinance::Error => e
  raise unless e.message.start_with?("Invalid response format")
  rates = fallback_provider.fetch_exchange_rates(from: "EUR", to: "USD", start_date: s, end_date: e)
end
Defensive patterns

Strategy: retry

Try / catch

begin
  provider.fetch_exchange_rates(from:, to:, start_date:, end_date:)
rescue Provider::YahooFinance::Error => e
  raise unless e.message.start_with?("Invalid response format")
  # Yahoo served non-JSON (block page) — back off, then fall back
  retry if (attempts += 1) < 2
  fallback_provider.fetch_exchange_rates(from:, to:, start_date:, end_date:)
end

Prevention

When it happens

Trigger: Yahoo Finance (an unofficial, unauthenticated API) returning an HTML consent/captcha page, a 429 HTML error page, or an empty body on the chart endpoint; a proxy or corporate firewall mangling the response; CDN edge returning compressed/HTML content the client misreads.

Common situations: Yahoo throttling unauthenticated scrapers; IP blocked or geo-consent interstitials (EU cookie walls); datacenter egress IPs flagged as bots; response shape/encoding changes after Yahoo deploys updates.

Related errors


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