{"record":{"id":"8e8ecc2a93ceaa2a","repo":"we-promise/sure","slug":"parsed-note","errorCode":null,"errorMessage":"parsed[\"Note\"]","messagePattern":"parsed\\[\"Note\"\\]","errorType":"exception","errorClass":"Provider::AlphaVantage::RateLimitError","httpStatus":null,"severity":"warning","filePath":"app/models/provider/alpha_vantage.rb","lineNumber":326,"sourceCode":"      when \"STO\" then \"SEK\"\n      when \"CPH\" then \"DKK\"\n      when \"OSL\" then \"NOK\"\n      else \"USD\"\n      end\n\n      Rails.cache.write(cache_key, currency, expires_in: 24.hours)\n      currency\n    end\n\n    # Checks for Alpha Vantage-specific error responses.\n    # Alpha Vantage returns errors as JSON keys rather than HTTP status codes.\n    def check_api_error!(parsed)\n      return unless parsed.is_a?(Hash)\n\n      # Rate limit: Alpha Vantage returns a \"Note\" key when rate-limited\n      if parsed[\"Note\"].present?\n        Rails.logger.warn(\"AlphaVantage rate limit: #{parsed[\"Note\"]}\")\n        raise RateLimitError, parsed[\"Note\"]\n      end\n\n      # General info/limit messages\n      if parsed[\"Information\"].present?\n        Rails.logger.warn(\"AlphaVantage info: #{parsed[\"Information\"]}\")\n        raise RateLimitError, parsed[\"Information\"]\n      end\n\n      # Explicit error messages for invalid parameters\n      if parsed[\"Error Message\"].present?\n        raise Error, \"API error: #{parsed[\"Error Message\"]}\"\n      end\n    end\nend\n","sourceCodeStart":308,"sourceCodeEnd":341,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/alpha_vantage.rb#L308-L341","documentation":"check_api_error! raises Provider::AlphaVantage::RateLimitError with the raw value of the response's 'Note' key. Alpha Vantage signals upstream rate limiting with HTTP 200 plus a JSON 'Note' field (e.g. call-frequency messages) rather than a 429 status; the provider detects this and converts it to a typed rate-limit error after warning to the log.","triggerScenarios":"Exceeding Alpha Vantage's upstream per-minute/per-day call frequency for your API key tier — distinct from the local daily counter; bursts of requests after the interval throttle lapses; shared key used by another app.","commonSituations":"Free-tier key hitting the upstream 25/day or 5/min limit while the local counter is lower; key used in multiple environments; clock skew between local throttle and upstream window.","solutions":["Back off and retry with exponential delay (upstream limits are time-windowed), or reschedule to the next day.","Upgrade the Alpha Vantage plan or lower request frequency (raise MIN_REQUEST_INTERVAL/batch more).","Ensure only one environment uses the key; duplicate consumers multiply upstream counts.","Rescue Provider::AlphaVantage::RateLimitError and surface it in provider usage/health UI instead of failing the job."],"exampleFix":"# before\nprovider.fetch_security_prices(symbol: s, start_date: from, end_date: to)\n\n# after\nattempts = 0\nbegin\n  provider.fetch_security_prices(symbol: s, start_date: from, end_date: to)\nrescue Provider::AlphaVantage::RateLimitError\n  attempts += 1\n  raise if attempts > 3\n  sleep(60 * attempts) && retry\nend","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"begin\n  provider.fetch_security_prices(symbol: s, start_date: a, end_date: b)\nrescue Provider::AlphaVantage::RateLimitError => e\n  sleep(60 * (attempt += 1))\n  retry if attempt < 3\n  raise\nend","preventionTips":["Honor the local MIN_REQUEST_INTERVAL throttle; do not parallelize AV calls.","Use a dedicated API key per environment so counts are predictable.","Treat 'Note' responses as upstream 429s: back off, then retry with jitter."],"tags":["alpha-vantage","rate-limit","provider","retry","ruby"],"backgroundTag":"api-rate-limit-exceeded","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}