we-promise/sure · error · Provider::TwelveData::InvalidExchangeRateError
API error (code: #{error_code}): #{error_message}
Error message
API error (code: #{error_code}): #{error_message} What it means
Provider::TwelveData::InvalidExchangeRateError raised in fetch_exchange_rates when the response body has no "values" array after both attempts: the /time_series endpoint (direct pair, 1 credit) and the /time_series/cross fallback (5 credits). check_api_error! already passed, so the API responded successfully but with no data payload for the pair/date range.
Source
Thrown at app/models/provider/twelve_data.rb:114
Rails.logger.info("#{self.class.name}: Currency pair #{from}/#{to} not available, fetching via time_series/cross API")
throttle_request(credits: 5)
response = client.get("#{base_url}/time_series/cross") do |req|
req.params["base"] = from
req.params["quote"] = to
req.params["start_date"] = start_date.to_s
req.params["end_date"] = end_date.to_s
req.params["interval"] = "1day"
end
parsed = JSON.parse(response.body)
check_api_error!(parsed)
data = parsed.dig("values")
end
if data.nil?
error_message = parsed.dig("message") || "No data returned"
error_code = parsed.dig("code") || "unknown"
raise InvalidExchangeRateError, "API error (code: #{error_code}): #{error_message}"
end
data.map do |resp|
rate = resp.dig("close")
date = resp.dig("datetime")
if rate.nil? || rate.to_f <= 0
Rails.logger.warn("#{self.class.name} returned invalid rate data for pair from: #{from} to: #{to} on: #{date}. Rate data: #{rate.inspect}")
next
end
Rate.new(date: date.to_date, from:, to:, rate:)
end.compact
end
end
# ================================
# Securities
# ================================View on GitHub (pinned to e69894adb9)
Solutions
- Verify the currency pair with a direct API call (curl 'https://api.twelvedata.com/time_series?symbol=EUR/USD&apikey=...') to see whether values are returned at all
- Widen the date range — single-day or weekend-only windows commonly come back empty
- Check the error_code/message embedded in the message: code 429 means rate limit (raise came after throttle), other codes indicate plan/pair restrictions
- Fall back to another exchange-rate provider for pairs Twelve Data does not cover
Example fix
// before
rates = provider.fetch_exchange_rates(from: "TRY", to: "KRW", start_date: d, end_date: d)
// after
response = provider.fetch_exchange_rates(from: "TRY", to: "KRW", start_date: d - 7.days, end_date: d)
if response.error.present?
Rails.logger.warn("TwelveData FX failed: #{response.error.message}")
response = fallback_provider.fetch_exchange_rates(from: "TRY", to: "KRW", start_date: d - 7.days, end_date: d)
end
rates = response.data Defensive patterns
Strategy: fallback
Validate before calling
response = provider.fetch_exchange_rates(from:, to:, start_date: date - 7.days, end_date: date) if response.error.present? # use fallback provider rather than raising into the caller end
Try / catch
begin
provider.fetch_exchange_rates(from:, to:, start_date:, end_date:)
rescue Provider::TwelveData::InvalidExchangeRateError => e
Rails.logger.warn("TwelveData FX unavailable for #{from}/#{to}: #{e.message}")
fallback_provider.fetch_exchange_rates(from:, to:, start_date:, end_date:)
end Prevention
- Widen date ranges — single-day and weekend-only windows come back empty
- Pre-check pair support with a cached capability list or cheap /exchange_rate call before time_series
- Keep a second FX provider wired for pairs Twelve Data doesn't cover
When it happens
Trigger: Fetching exchange rates for a pair Twelve Data has no time series for (both direct and cross listings empty), a date range where no data exists (weekend/holiday-only range), or an unsupported/exotic currency code that returns JSON without a values key.
Common situations: Syncing an account with an exotic currency (e.g. TRY/KRW crosses); requesting a single weekend date; a typo'd currency code that silently yields an empty response; free-plan limits returning empty bodies instead of explicit errors.
Related errors
- Failed to fetch exchange rates: #{rates_response.error.messa
- No chart data found for currency pair #{from}/#{to}
- bad_request
- Trading 212 authentication failed (#{response.code}). Check
- No prices found for security #{symbol} on date #{date}
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/ffb1afeca0d466a0.
Report an issue: GitHub.