we-promise/sure · error · Provider::EnableBanking::EnableBankingError

request_failed

request_failed

Error message

Exception during GET request: #{e.message}

What it means

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.

Source

Thrown at app/models/provider/enable_banking.rb:36

  def initialize(application_id:, client_certificate:)
    @application_id = application_id
    @private_key = extract_private_key(client_certificate)
  end

  # Get list of available ASPSPs (banks) for a country
  # @param country [String] ISO 3166-1 alpha-2 country code (e.g., "GB", "DE", "FR")
  # @return [Array<Hash>] List of ASPSPs
  def get_aspsps(country:)
    response = self.class.get(
      "#{BASE_URL}/aspsps",
      headers: auth_headers,
      query: { country: country }
    )

    handle_response(response)
  rescue SocketError, Net::OpenTimeout, Net::ReadTimeout => e
    raise EnableBankingError.new("Exception during GET request: #{e.message}", :request_failed)
  end

  # Initiate authorization flow - returns a redirect URL for the user
  # @param aspsp_name [String] Name of the ASPSP from get_aspsps
  # @param aspsp_country [String] Country code for the ASPSP
  # @param redirect_url [String] URL to redirect user back to after auth
  # @param state [String, nil] State parameter to pass through
  # @param psu_type [String] "personal" or "business"
  # @param maximum_consent_validity [Integer, nil] Max consent duration in seconds from ASPSP (nil = use 90 days)
  # @param language [String, nil] Two-letter language code (e.g. "fr", "en")
  # @param auth_method [String, nil] Name of a specific authentication method to use (from the ASPSP's
  #   auth_methods list). Required to drive DECOUPLED/EMBEDDED banks that expose several methods; when nil
  #   Enable Banking falls back to the ASPSP's default method.
  # @return [Hash] Contains :url and :authorization_id
  def start_authorization(aspsp_name:, aspsp_country:, redirect_url:, state: nil,
                          psu_type: "personal", maximum_consent_validity: nil, language: nil, auth_method: nil)
    max_seconds = maximum_consent_validity ? [ maximum_consent_validity, 1 ].max : 90.days.to_i
    valid_until = [ Time.current + max_seconds.seconds, Time.current + 90.days ].min

View on GitHub (pinned to e69894adb9)

Solutions

  1. Verify reachability from the same environment: curl -v 'https://api.enablebanking.com/aspsps?country=FI'
  2. If DNS fails, fix resolver/VPN; if connect times out, allow egress to api.enablebanking.com:443
  3. Retry with backoff — this endpoint is a plain read, safe to retry
  4. If ReadTimeout recurs, check Enable Banking status before raising the client timeout above 120s

Example fix

# before
banks = client.get_aspsps(country: "DE")

# after
attempts = 0
begin
  banks = client.get_aspsps(country: "DE")
rescue Provider::EnableBanking::EnableBankingError => e
  raise unless e.error_type == :request_failed && (attempts += 1) <= 3
  sleep(2**attempts)
  retry
end
Defensive patterns

Strategy: retry

Validate before calling

require "socket"

def enable_banking_reachable?
  Socket.tcp("api.enablebanking.com", 443, connect_timeout: 5).close
  true
rescue SocketError, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
  false
end

Type guard

def eb_request_failed?(error)
  error.is_a?(Provider::EnableBanking::EnableBankingError) && error.error_type == :request_failed
end

Try / catch

attempts = 0
begin
  banks = client.get_aspsps(country: "DE")
rescue Provider::EnableBanking::EnableBankingError => e
  raise unless e.error_type == :request_failed && (attempts += 1) <= 3
  sleep(2**attempts)
  retry
end

Prevention

When it happens

Trigger: 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).

Common situations: Local development without internet or with a VPN that blocks the host, CI containers with restricted egress, DNS outages, transient upstream slowness.

Related errors


AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21). Data as JSON: /api/errors/aa8c8a9bca812151. Report an issue: GitHub.