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

Failed to obtain Yahoo Finance crumb

Error message

Failed to obtain Yahoo Finance crumb

What it means

Raised when Yahoo Finance's getcrumb endpoint answers non-429 non-success (e.g. 401/403/5xx), or answers 200 with a crumb that fails valid_crumb? (blank or in INVALID_CRUMBS). The class is AuthenticationError for a bad/absent crumb but RateLimitError when the body literally says 'too many requests' - Yahoo signals throttling via the crumb text.

Source

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

          details: { status: cookie_response.status }
        )
      end

      cookie = extract_cookie(cookie_response)
      cookie_max_age = extract_cookie_max_age(cookie_response)
      raise AuthenticationError, "Failed to obtain Yahoo Finance cookie" if cookie.blank?

      crumb_response = authentication_client.get("#{base_url}/v1/test/getcrumb") do |req|
        req.headers["Cookie"] = cookie
      end
      if crumb_response.status == 429
        raise RateLimitError.new(
          "Yahoo Finance rate limit exceeded",
          details: { status: crumb_response.status }
        )
      end
      unless crumb_response.success?
        raise AuthenticationError.new(
          "Failed to obtain Yahoo Finance crumb",
          details: { status: crumb_response.status }
        )
      end

      crumb = crumb_response.body.to_s.strip
      unless valid_crumb?(crumb)
        error_class = INVALID_CRUMBS.include?(crumb.downcase) ? RateLimitError : AuthenticationError
        raise error_class.new(
          "Failed to obtain Yahoo Finance crumb",
          details: { status: crumb_response.status }
        )
      end

      cache_duration = [ cookie_max_age || MAX_CRUMB_CACHE_DURATION, MAX_CRUMB_CACHE_DURATION ].min
      [ cookie, crumb, cache_duration ]
    end

View on GitHub (pinned to e69894adb9)

Solutions

  1. If the error is RateLimitError (body 'Too Many Requests'), back off for minutes and redo the whole cookie+crumb handshake
  2. If AuthenticationError: redo the handshake with a fresh cookie and verify extract_cookie pulled a real cookie (not blank)
  3. For EU regions, ensure the handshake satisfies Yahoo's consent flow or egress from a non-consent-walled region
  4. If a new junk crumb string appears consistently, add it to INVALID_CRUMBS and treat it as throttling

Example fix

# before
cookie, crumb = provider.send(:request_cookie_and_crumb, client)

# after - retry handshake once with fresh cookie, then give up gracefully
begin
  cookie, crumb = provider.send(:request_cookie_and_crumb, client)
rescue Provider::YahooFinance::AuthenticationError => e
  Rails.cache.delete("yahoo_finance_crumb_cache")
  retry if (attempts += 1) == 1
  raise
end
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

def yahoo_auth_failed?(err)
  err.is_a?(Provider::YahooFinance::AuthenticationError)
end

Try / catch

attempts = 0
begin
  provider.fetch_quotes(symbols)
rescue Provider::YahooFinance::AuthenticationError, Provider::YahooFinance::RateLimitError => e
  Rails.cache.delete(provider.class::HEALTH_STATUS_CACHE_KEY)
  retry if (attempts += 1) == 1 # one fresh handshake
  fall_back_to_alternate_provider(e)
end

Prevention

When it happens

Trigger: GET /v1/test/getcrumb returns 401/403/5xx (cookie rejected, consent not satisfied); crumb body is empty; crumb body is 'Too Many Requests' (mapped to RateLimitError via INVALID_CRUMBS).

Common situations: The fc.yahoo.com cookie missing required consent cookies (EU consent wall for EU egress IPs); Yahoo changing the crumb contract (new sentinel values not yet in INVALID_CRUMBS); cookie expired between the two requests; IP reputation issues making Yahoo hand out junk crumbs.

Related errors


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