we-promise/sure · error · EnableBankingError

validation_error

validation_error

Error message

Validation error from Enable Banking API: #{response.body}

What it means

Raised when Enable Banking returns HTTP 422 - the request body/query is semantically invalid. The body is parsed with the strict parser (parse_response_body) and attached as response_data, so field-level API errors are inspectable. In this codebase the dominant 422 is WRONG_TRANSACTIONS_PERIOD: get_account_transactions already auto-retries it once with the ASPSP-suggested date_from, then walks fallback windows of 89/60/30 days; this error only escapes when those retries are exhausted or a different endpoint (POST /auth, POST /sessions) sends a bad payload.

Source

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

      case response.code
      when 200, 201
        parse_response_body(response)
      when 204
        {}
      when 400
        response_data = parse_error_response_body(response)
        raise EnableBankingError.new("Bad request to Enable Banking API: #{response.body}", :bad_request, response_data: response_data)
      when 401
        raise EnableBankingError.new("Invalid credentials or expired JWT", :unauthorized)
      when 403
        raise EnableBankingError.new("Access forbidden - check your application permissions", :access_forbidden)
      when 404
        raise EnableBankingError.new("Resource not found", :not_found)
      when 408
        raise EnableBankingError.new("Request timeout from Enable Banking API", :timeout)
      when 422
        response_data = parse_response_body(response)
        raise EnableBankingError.new("Validation error from Enable Banking API: #{response.body}", :validation_error, response_data: response_data)
      when 429
        raise EnableBankingError.new("Rate limit exceeded. Please try again later.", :rate_limited)
      else
        response_data = parse_error_response_body(response)
        raise EnableBankingError.new("Failed to fetch data: #{response.code} #{response.message} - #{response.body}", :fetch_failed, response_data: response_data)
      end
    end

    def parse_error_response_body(response)
      return {} if response.body.blank?

      JSON.parse(response.body, symbolize_names: true)
    rescue JSON::ParserError
      { raw_body: response.body.to_s }
    end

    def parse_response_body(response)
      return {} if response.body.blank?

View on GitHub (pinned to e69894adb9)

Solutions

  1. Inspect e.response_data (e.g. response_data[:message] / error name) to see which field Enable Banking rejected
  2. Clamp date_from to max(consent start, 89 days ago) before calling get_account_transactions so no retry chain is needed
  3. Use e.wrong_transactions_period? / e.corrected_date_from on the raised error instead of string-matching the body
  4. For auth/session 422s, verify redirect_url, state and the aspsp name/country against values returned by get_aspsps

Example fix

// before
provider.get_account_transactions(account_id: id, date_from: account.consent_given_at - 2.years, date_to: Date.current)

// after
earliest = [account.consent_given_at.to_date, 89.days.ago.to_date].max
provider.get_account_transactions(account_id: id, date_from: earliest, date_to: Date.current)
Defensive patterns

Strategy: validation

Validate before calling

earliest = [account.consent_given_at.to_date, 89.days.ago.to_date].compact.max
provider.get_account_transactions(
  account_id: id,
  date_from: earliest,
  date_to: [Date.current, account.consent_expires_at.to_date].compact.min
)

Type guard

def wrong_transactions_period?(error)
  error.is_a?(Provider::EnableBanking::EnableBankingError) &&
    (error.wrong_transactions_period? || error.error_type == :validation_error)
end

Try / catch

begin
  provider.get_account_transactions(account_id: id, date_from: from, date_to: to)
rescue Provider::EnableBanking::EnableBankingError => e
  raise unless e.wrong_transactions_period?
  provider.get_account_transactions(account_id: id,
    date_from: e.corrected_date_from || 30.days.ago.to_date, date_to: to)
end

Prevention

When it happens

Trigger: get_account_transactions with date_from older than the PSD2 consent grants (consent start or ~90 days), where even the 30-day fallback window is rejected; start_authorization with a malformed redirect_url or aspsp name/country pair; create_session with an already-consumed authorization code.

Common situations: European banks capping transaction history to the consent period (some PT banks return WRONG_TRANSACTIONS_PERIOD without a corrected date_from, the exact case the fallback windows were added for), consent re-authorized so the allowed window moved forward, hand-built aspsps name/country values that don't match get_aspsps output.

Related errors


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