we-promise/sure · error · Provider::Simplefin::SimplefinError
request_failed
request_failed
Error message
Exception during #{operation_name}: #{e.message} What it means
The catch-all rescue in Provider::Simplefin.with_retries: any exception that is not a SimplefinError and not a retryable network error is logged as 'non-retryable' and re-raised wrapped in SimplefinError(:request_failed). The original class name is only in the log line, not in the message, so the Rails log is the key diagnostic.
Source
Thrown at app/models/provider/simplefin.rb:165
sleep(delay) if backoff && delay.to_f.positive?
retry
else
Rails.logger.error(
"SimpleFin API: #{operation_name} failed after #{max_retries} retries: " \
"#{e.class}: #{e.message}"
)
raise SimplefinError.new(
"Network error after #{max_retries} retries: #{e.message}",
:network_error
)
end
rescue SimplefinError => e
# Preserve original error type and message.
raise
rescue => e
# Non-retryable errors are logged and re-raised immediately
Rails.logger.error "SimpleFin API: #{operation_name} failed with non-retryable error: #{e.class}: #{e.message}"
raise SimplefinError.new("Exception during #{operation_name}: #{e.message}", :request_failed)
end
end
# Calculate delay with exponential backoff and jitter
def calculate_retry_delay(retry_count)
# Exponential backoff: 2^retry * initial_delay
base_delay = INITIAL_RETRY_DELAY * (2 ** (retry_count - 1))
# Add jitter (0-25% of base delay) to prevent thundering herd
jitter = base_delay * rand * 0.25
# Cap at max delay
[ base_delay + jitter, MAX_RETRY_DELAY ].min
end
end
View on GitHub (pinned to e69894adb9)
Solutions
- Grep the log for 'failed with non-retryable error' - the e.class recorded there (e.g. OpenSSL::SSL::SSLError vs JSON::ParserError) identifies the family
- For SSL errors, verify the cert chain with curl -v and check whether a proxy intercepts TLS; do not disable verification
- For parse/type errors, reproduce the raw request with curl and inspect the actual response body/content-type
- Fix the root cause rather than retrying - this wrapper deliberately does not retry because these errors are deterministic
Defensive patterns
Strategy: try-catch
Try / catch
begin
simplefin.get_accounts
rescue Provider::Simplefin::SimplefinError => e
if e.error_type == :request_failed
report_with_context(e.message) # deterministic bug or env issue - do not retry
else
raise
end
end Prevention
- Retrying this class of error is wasted work - it wraps deterministic failures
- Capture the Rails log line with the original e.class when reporting
- Smoke-test credential URLs and TLS on new deploy environments before enabling syncs
When it happens
Trigger: Non-network failures inside the HTTP operation: JSON::ParserError while parsing a 2xx body, OpenSSL::SSL::SSLError from a bad TLS handshake/cert, TypeError/ArgumentError from a malformed base_url (e.g. access URL stored with spaces), or any unexpected bug in the request block.
Common situations: Access URL saved with a typo that survives URI parsing but breaks later; a TLS-intercepting corporate proxy presenting an untrusted cert; SimpleFIN returning HTML instead of JSON on a 200; code changes introducing a NoMethodError inside the block.
Related errors
- Please provide a name and a complete US address (street, cit
- fetch_failed
- unknown
- unknown
- token_compromised
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/e46f1b80eaf9f4e8.
Report an issue: GitHub.