we-promise/sure · error · Provider::TwelveData::Error
API error (code: #{parsed["code"]}): #{parsed["message"] ||
Error message
API error (code: #{parsed["code"]}): #{parsed["message"] || "Unknown error"} What it means
Provider::TwelveData::Error raised by check_api_error! for any non-429 code field in the response body. Twelve Data returns errors as JSON with a numeric code and message (400 bad parameters, 401 invalid key, 403 plan restrictions, 4xx/5xx-style codes) even with HTTP 200, and this guard converts them into a typed provider error.
Source
Thrown at app/models/provider/twelve_data.rb:332
@last_request_time = Time.current
end
def min_request_interval
ENV.fetch("TWELVE_DATA_MIN_REQUEST_INTERVAL", MIN_REQUEST_INTERVAL).to_f
end
def max_requests_per_minute
ENV.fetch("TWELVE_DATA_MAX_REQUESTS_PER_MINUTE", 7).to_i
end
def check_api_error!(parsed)
return unless parsed.is_a?(Hash) && parsed["code"].present?
if parsed["code"] == 429
raise RateLimitError, parsed["message"] || "Rate limit exceeded"
end
raise Error, "API error (code: #{parsed["code"]}): #{parsed["message"] || "Unknown error"}"
end
def default_error_transformer(error)
case error
when RateLimitError
error
when Faraday::TooManyRequestsError
RateLimitError.new("TwelveData rate limit exceeded", details: error.response&.dig(:body))
when Faraday::Error
self.class::Error.new(error.message, details: error.response&.dig(:body))
else
self.class::Error.new(error.message)
end
end
end
View on GitHub (pinned to e69894adb9)
Solutions
- Read the code and message in the error string — code 401 means the apikey header is wrong, 400 means fix params, plan names mean upgrade
- Test the same request with curl and the same apikey to confirm the account/plan can access the endpoint
- For plan-upgrade messages, check Provider::TwelveData.plan_upgrade_required?(e.message) / extract_required_plan(e.message) and surface a plan requirement to the user
- Regenerate the API key in the Twelve Data dashboard if 401 persists
Example fix
// before
begin
provider.fetch_security_info(symbol: "AAPL", exchange_operating_mic: "XNAS")
rescue Provider::TwelveData::Error
raise
end
// after
begin
provider.fetch_security_info(symbol: "AAPL", exchange_operating_mic: "XNAS")
rescue Provider::TwelveData::Error => e
if Provider::TwelveData.plan_upgrade_required?(e.message)
required = Provider::TwelveData.extract_required_plan(e.message)
notify_user("Twelve Data #{required} plan required for this endpoint")
else
raise
end
end Defensive patterns
Strategy: try-catch
Validate before calling
unless provider.healthy? # Twelve Data /api_usage failed — skip the sync rather than eating body-coded errors end
Try / catch
begin
provider.fetch_security_info(symbol:, exchange_operating_mic:)
rescue Provider::TwelveData::Error => e
if Provider::TwelveData.plan_upgrade_required?(e.message)
handle_plan_required(Provider::TwelveData.extract_required_plan(e.message))
else
raise
end
end Prevention
- Use the built-in plan_upgrade_required?/extract_required_plan helpers to classify plan errors
- Call provider.healthy? before batch operations to catch bad keys early
- Log the code+message pair — Twelve Data's numeric codes map to distinct fixes
When it happens
Trigger: Invalid or revoked apikey (code 401), endpoint not in your plan (grow/grow/pro codes with 'available starting with PRO' messages — see PLAN_UPGRADE_PATTERN), malformed symbol or date params (code 400), or unsupported parameter combinations.
Common situations: API key expired or mistyped; free plan hitting an endpoint that requires a paid tier; passing mic_code/symbol combos the endpoint rejects; environment differences where the staging key belongs to a different plan.
Related errors
- API error (code: #{error_code}): #{error_message}
- No prices found for security #{symbol} on date #{date}
- 429
- bad_request
- unauthorized
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/f7688bcc998cbc29.
Report an issue: GitHub.