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
- Inspect e.response_data (e.g. response_data[:message] / error name) to see which field Enable Banking rejected
- Clamp date_from to max(consent start, 89 days ago) before calling get_account_transactions so no retry chain is needed
- Use e.wrong_transactions_period? / e.corrected_date_from on the raised error instead of string-matching the body
- 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
- Clamp date_from to the consent start date before the first call
- Track consent_given_at per connection and never request earlier than it
- For auth/session calls, source aspsp name/country from get_aspsps output rather than hand-typed values
- Log e.response_data whenever a 422 escapes - it carries the field-level reason
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.