{"record":{"id":"aa8c8a9bca812151","repo":"we-promise/sure","slug":"request-failed-aa8c8a","errorCode":"request_failed","errorMessage":"Exception during GET request: #{e.message}","messagePattern":"Exception during GET request: #(.+?)","errorType":"exception","errorClass":"Provider::EnableBanking::EnableBankingError","httpStatus":null,"severity":"error","filePath":"app/models/provider/enable_banking.rb","lineNumber":36,"sourceCode":"\n  def initialize(application_id:, client_certificate:)\n    @application_id = application_id\n    @private_key = extract_private_key(client_certificate)\n  end\n\n  # Get list of available ASPSPs (banks) for a country\n  # @param country [String] ISO 3166-1 alpha-2 country code (e.g., \"GB\", \"DE\", \"FR\")\n  # @return [Array<Hash>] List of ASPSPs\n  def get_aspsps(country:)\n    response = self.class.get(\n      \"#{BASE_URL}/aspsps\",\n      headers: auth_headers,\n      query: { country: country }\n    )\n\n    handle_response(response)\n  rescue SocketError, Net::OpenTimeout, Net::ReadTimeout => e\n    raise EnableBankingError.new(\"Exception during GET request: #{e.message}\", :request_failed)\n  end\n\n  # Initiate authorization flow - returns a redirect URL for the user\n  # @param aspsp_name [String] Name of the ASPSP from get_aspsps\n  # @param aspsp_country [String] Country code for the ASPSP\n  # @param redirect_url [String] URL to redirect user back to after auth\n  # @param state [String, nil] State parameter to pass through\n  # @param psu_type [String] \"personal\" or \"business\"\n  # @param maximum_consent_validity [Integer, nil] Max consent duration in seconds from ASPSP (nil = use 90 days)\n  # @param language [String, nil] Two-letter language code (e.g. \"fr\", \"en\")\n  # @param auth_method [String, nil] Name of a specific authentication method to use (from the ASPSP's\n  #   auth_methods list). Required to drive DECOUPLED/EMBEDDED banks that expose several methods; when nil\n  #   Enable Banking falls back to the ASPSP's default method.\n  # @return [Hash] Contains :url and :authorization_id\n  def start_authorization(aspsp_name:, aspsp_country:, redirect_url:, state: nil,\n                          psu_type: \"personal\", maximum_consent_validity: nil, language: nil, auth_method: nil)\n    max_seconds = maximum_consent_validity ? [ maximum_consent_validity, 1 ].max : 90.days.to_i\n    valid_until = [ Time.current + max_seconds.seconds, Time.current + 90.days ].min","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/enable_banking.rb#L18-L54","documentation":"Raised by Provider::EnableBanking#get_aspsps when the GET to https://api.enablebanking.com/aspsps fails at the transport layer with SocketError (DNS resolution or routing failure), Net::OpenTimeout (connect timeout), or Net::ReadTimeout (response exceeded the 120s read timeout). It is wrapped as EnableBankingError(:request_failed) with the original transport message preserved.","triggerScenarios":"Calling get_aspsps(country: \"XX\") in an environment where api.enablebanking.com cannot be resolved (SocketError), outbound 443 is blocked by firewall/container policy (OpenTimeout), or the endpoint hangs past the 120s HTTParty timeout (ReadTimeout).","commonSituations":"Local development without internet or with a VPN that blocks the host, CI containers with restricted egress, DNS outages, transient upstream slowness.","solutions":["Verify reachability from the same environment: curl -v 'https://api.enablebanking.com/aspsps?country=FI'","If DNS fails, fix resolver/VPN; if connect times out, allow egress to api.enablebanking.com:443","Retry with backoff — this endpoint is a plain read, safe to retry","If ReadTimeout recurs, check Enable Banking status before raising the client timeout above 120s"],"exampleFix":"# before\nbanks = client.get_aspsps(country: \"DE\")\n\n# after\nattempts = 0\nbegin\n  banks = client.get_aspsps(country: \"DE\")\nrescue Provider::EnableBanking::EnableBankingError => e\n  raise unless e.error_type == :request_failed && (attempts += 1) <= 3\n  sleep(2**attempts)\n  retry\nend","handlingStrategy":"retry","validationCode":"require \"socket\"\n\ndef enable_banking_reachable?\n  Socket.tcp(\"api.enablebanking.com\", 443, connect_timeout: 5).close\n  true\nrescue SocketError, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH\n  false\nend","typeGuard":"def eb_request_failed?(error)\n  error.is_a?(Provider::EnableBanking::EnableBankingError) && error.error_type == :request_failed\nend","tryCatchPattern":"attempts = 0\nbegin\n  banks = client.get_aspsps(country: \"DE\")\nrescue Provider::EnableBanking::EnableBankingError => e\n  raise unless e.error_type == :request_failed && (attempts += 1) <= 3\n  sleep(2**attempts)\n  retry\nend","preventionTips":["Probe api.enablebanking.com:443 reachability at worker boot in restricted environments","Cache the ASPSP list briefly — it changes rarely and reduces calls","Validate country format client-side before spending a network call","Distinguish :request_failed (transport) from API-status errors before choosing retry vs reauth"],"tags":["enable-banking","network","dns","timeout","httparty"],"backgroundTag":"network-timeout","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}