we-promise/sure · error · Provider::Eodhd::Error
API error: #{parsed["error"]}
Error message
API error: #{parsed["error"]} What it means
Raised as Provider::Eodhd::Error when a parsed EODHD response is a Hash containing a present 'error' key. EODHD signals failures in-band: HTTP status is often 200 while the JSON body carries {"error": "..."}. check_api_error! runs on every parsed response (search, EOD prices, fundamentals) before format validation, converting these in-band errors into a Ruby exception with the upstream message preserved verbatim.
Source
Thrown at app/models/provider/eodhd.rb:304
# Uses atomic increment-then-check to avoid TOCTOU races between concurrent workers.
def enforce_daily_limit!
new_count = Rails.cache.increment(daily_cache_key, 1, expires_in: 24.hours).to_i
if new_count > max_requests_per_day
raise RateLimitError, "EODHD daily rate limit of #{max_requests_per_day} requests exhausted"
end
end
# throttle_request and min_request_interval provided by RateLimitable
def max_requests_per_day
ENV.fetch("EODHD_MAX_REQUESTS_PER_DAY", MAX_REQUESTS_PER_DAY).to_i
end
def check_api_error!(parsed)
return unless parsed.is_a?(Hash) && parsed["error"].present?
raise Error, "API error: #{parsed["error"]}"
end
end
View on GitHub (pinned to e69894adb9)
Solutions
- Read the message text: 'Invalid API key/Token' → fix credentials; 'Exceeded ... limit' → EODHD-side quota (distinct from the local RateLimitError); 'Not found' → bad symbol/exchange suffix
- Verify the token against EODHD's user/details endpoint to confirm validity and remaining quota
- For quota errors, upgrade the plan or reduce request volume (see the local daily limiter) — retrying will not help
- For symbol errors, re-run a search_securities lookup to get the correct ticker/exchange mapping
- Store the corrected token in the provider settings UI / credential store rather than ENV snapshots to avoid stale copies
Example fix
# before: token errors surface as a generic raised string, caller retries pointlessly begin provider.fetch_security_prices(symbol: "AAPL.US", start_date: from, end_date: to) rescue Provider::Eodhd::Error => e retry_job end # after: branch on the upstream message; only retry non-auth, non-quota failures rescue Provider::Eodhd::Error => e raise if e.message.match?(/Invalid API key|Exceeded/i) retry_job if e.message.match?(/temporary|timeout/i)
Defensive patterns
Strategy: try-catch
Validate before calling
# Validate the token's account status before starting syncs
user_info = client.get("#{base_url}/api/user-details") # adjust per your client
raise if user_info.body.include?('"error"') # surface token problems up front Try / catch
begin
data = provider.fetch_security_prices(...)
rescue Provider::Eodhd::Error => e
case e.message
when /Invalid API key|Token/i then disconnect_provider("EODHD auth failed: #{e.message}")
when /Exceeded|limit/i then schedule_retry_tomorrow
else raise
end
end Prevention
- Store EODHD tokens in the provider settings store and validate them on save (call a cheap endpoint)
- Alert on quota-type in-band errors separately from transient ones — retrying quota errors wastes budget
- Keep the local daily limiter (see RateLimitError) below EODHD's plan quota to hit your own guard first
- Log the exact upstream message via DebugLogEntry for support triage
When it happens
Trigger: Any EODHD call whose body includes a non-blank 'error' field: invalid or expired api_token ('Invalid API key'), unknown symbol ('Not found'), exceeding the account's request quota ('Exceeded the daily requests limit'), or restricted access to a data feed the token does not include. Triggered by the same GETs as search_securities and fetch_security_prices.
Common situations: Expired or typo'd API token after credentials rotation, free-tier token hitting EODHD's own (separate from the local) request limit, requesting US exchanges on a plan without US data access, delisted symbols, and environments sharing one token across many app instances.
Related errors
- EODHD daily rate limit of #{max_requests_per_day} requests e
- Unexpected response format from search API
- No prices found for security #{symbol} on date #{date}
- rate_limited
- rate_limited
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/89753ea23709bb4c.
Report an issue: GitHub.