{"record":{"id":"7aee135fd9baf442","repo":"we-promise/sure","slug":"server-error","errorCode":"server_error","errorMessage":"IndexaCapital server error (#{response.code}). Please try again later.","messagePattern":"IndexaCapital server error \\(#(.+?)\\)\\. Please try again later\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/models/provider/indexa_capital.rb","lineNumber":212,"sourceCode":"      when 200, 201\n        begin\n          JSON.parse(response.body, symbolize_names: true)\n        rescue JSON::ParserError => e\n          raise Error.new(\"Invalid JSON in response: #{e.message}\", :bad_response)\n        end\n      when 400\n        Rails.logger.error \"IndexaCapital API: Bad request - #{response.body}\"\n        raise Error.new(\"Bad request: #{response.body}\", :bad_request)\n      when 401\n        raise AuthenticationError.new(\"Invalid credentials\", :unauthorized)\n      when 403\n        raise AuthenticationError.new(\"Access forbidden - check your permissions\", :access_forbidden)\n      when 404\n        raise Error.new(\"Resource not found\", :not_found)\n      when 429\n        raise Error.new(\"Rate limit exceeded. Please try again later.\", :rate_limited)\n      when 500..599\n        raise Error.new(\"IndexaCapital server error (#{response.code}). Please try again later.\", :server_error)\n      else\n        Rails.logger.error \"IndexaCapital API: Unexpected response - Code: #{response.code}, Body: #{response.body}\"\n        raise Error.new(\"Unexpected error: #{response.code} - #{response.body}\", :unknown)\n      end\n    end\n\n    # Extract accounts array from /users/me response\n    # API returns: { accounts: [{ account_number: \"ABC12345\", type: \"mutual\", status: \"active\", ... }] }\n    def extract_accounts(user_data)\n      accounts = user_data[:accounts] || []\n      accounts.map do |acct|\n        {\n          account_number: acct[:account_number],\n          name: account_display_name(acct),\n          type: acct[:type],\n          status: acct[:status],\n          currency: \"EUR\",\n          raw: acct","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/indexa_capital.rb#L194-L230","documentation":"Any 500..599 from api.indexacapital.com maps to Error(:server_error) with the status code embedded. Important nuance: with_retries only retries transport exceptions - a 5xx HTTP response is returned normally by HTTParty and raised immediately by handle_response, so the provider does NOT auto-retry these even though they are usually transient.","triggerScenarios":"Indexa outage or deployment window; upstream database issues returning 500/503 on /users/me; load-shedding 503s during market-close spikes on /accounts/{n}/performance.","commonSituations":"Spanish market hours concentration (many users polling performance after close), Indexa maintenance windows, transient 502/504 from their gateway.","solutions":["Retry later with backoff - treat :server_error as transient and never invalidate credentials because of it","Schedule the retry on the next sync cycle rather than hammering inline","Capture DebugLogEntry with the status for pattern analysis (which endpoint, which hours)","If you want automatic handling, add a 5xx-aware retry around the call (see exampleFix) since with_retries will not do it"],"exampleFix":"# before\nprovider.list_accounts\n\n# after\nretries = 0\nbegin\n  provider.list_accounts\nrescue Provider::IndexaCapital::Error => e\n  retries += 1\n  retry if e.error_type == :server_error && retries <= 3 && sleep(2**retries)\n  raise\nend","handlingStrategy":"retry","validationCode":null,"typeGuard":"def indexa_server_error?(error)\n  error.is_a?(Provider::IndexaCapital::Error) && error.error_type == :server_error\nend","tryCatchPattern":"retries = 0\nbegin\n  provider.list_accounts\nrescue Provider::IndexaCapital::Error => e\n  retries += 1\n  retry if e.error_type == :server_error && retries <= 3 && sleep(2**retries)\n  RetryableSync.schedule(account, wait: 30.minutes) if retries > 3\n  raise\nend","preventionTips":["Know that with_retries only covers transport errors - 5xx needs your own retry wrapper","Never invalidate credentials on :server_error","Track which endpoint/hour 5xxs cluster to schedule around Indexa's busy windows","Cap retries and hand off to the scheduler instead of looping inline"],"tags":["indexa-capital","http-5xx","server-error","transient","upstream"],"backgroundTag":"upstream-5xx-server-error","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}