{"record":{"id":"f7688bcc998cbc29","repo":"we-promise/sure","slug":"api-error-code-parsed-code-parsed-mes","errorCode":null,"errorMessage":"API error (code: #{parsed[\"code\"]}): #{parsed[\"message\"] || \"Unknown error\"}","messagePattern":"API error \\(code: #(.+?)\\): #(.+?)","errorType":"exception","errorClass":"Provider::TwelveData::Error","httpStatus":null,"severity":"error","filePath":"app/models/provider/twelve_data.rb","lineNumber":332,"sourceCode":"      @last_request_time = Time.current\n    end\n\n    def min_request_interval\n      ENV.fetch(\"TWELVE_DATA_MIN_REQUEST_INTERVAL\", MIN_REQUEST_INTERVAL).to_f\n    end\n\n    def max_requests_per_minute\n      ENV.fetch(\"TWELVE_DATA_MAX_REQUESTS_PER_MINUTE\", 7).to_i\n    end\n\n    def check_api_error!(parsed)\n      return unless parsed.is_a?(Hash) && parsed[\"code\"].present?\n\n      if parsed[\"code\"] == 429\n        raise RateLimitError, parsed[\"message\"] || \"Rate limit exceeded\"\n      end\n\n      raise Error, \"API error (code: #{parsed[\"code\"]}): #{parsed[\"message\"] || \"Unknown error\"}\"\n    end\n\n    def default_error_transformer(error)\n      case error\n      when RateLimitError\n        error\n      when Faraday::TooManyRequestsError\n        RateLimitError.new(\"TwelveData rate limit exceeded\", details: error.response&.dig(:body))\n      when Faraday::Error\n        self.class::Error.new(error.message, details: error.response&.dig(:body))\n      else\n        self.class::Error.new(error.message)\n      end\n    end\nend\n","sourceCodeStart":314,"sourceCodeEnd":348,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/twelve_data.rb#L314-L348","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nbegin\n  provider.fetch_security_info(symbol: \"AAPL\", exchange_operating_mic: \"XNAS\")\nrescue Provider::TwelveData::Error\n  raise\nend\n\n// after\nbegin\n  provider.fetch_security_info(symbol: \"AAPL\", exchange_operating_mic: \"XNAS\")\nrescue Provider::TwelveData::Error => e\n  if Provider::TwelveData.plan_upgrade_required?(e.message)\n    required = Provider::TwelveData.extract_required_plan(e.message)\n    notify_user(\"Twelve Data #{required} plan required for this endpoint\")\n  else\n    raise\n  end\nend","handlingStrategy":"try-catch","validationCode":"unless provider.healthy?\n  # Twelve Data /api_usage failed — skip the sync rather than eating body-coded errors\nend","typeGuard":null,"tryCatchPattern":"begin\n  provider.fetch_security_info(symbol:, exchange_operating_mic:)\nrescue Provider::TwelveData::Error => e\n  if Provider::TwelveData.plan_upgrade_required?(e.message)\n    handle_plan_required(Provider::TwelveData.extract_required_plan(e.message))\n  else\n    raise\n  end\nend","preventionTips":["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"],"tags":["ruby","twelvedata","api-error","plan-limit","response-body-error"],"backgroundTag":"api-error-in-response-body","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}