we-promise/sure · error · Provider::Sophtron::Error
bad_request
bad_request
Error message
Bad request to Sophtron API: #{body} What it means
Raised by Provider::Sophtron's handle_response when the Sophtron API answers HTTP 400, meaning the request was well-formed enough to reach validation but the server rejected its parameters or body. The full response body is embedded in both the message and the error's details, since Sophtron's 400 bodies carry the specific validation message.
Source
Thrown at app/models/provider/sophtron.rb:357
def auth_headers(method:, api_path:)
{
"Authorization" => auth_header_for(method, api_path),
"Content-Type" => "application/json",
"Accept" => "application/json"
}
end
def handle_response(response, parse_json: true)
body = response.body.to_s
case response.code.to_i
when 200, 201, 204
return {} if body.strip.blank?
parse_json ? JSON.parse(body, symbolize_names: true) : parse_optional_json(body)
when 400
raise Error.new("Bad request to Sophtron API: #{body}", :bad_request, details: body)
when 401
raise Error.new("Invalid Sophtron User ID or Access Key", :unauthorized, details: body)
when 403
raise Error.new("Access forbidden by Sophtron", :access_forbidden, details: body)
when 404
raise Error.new("Sophtron resource not found", :not_found, details: body)
when 429
raise Error.new("Sophtron rate limit exceeded. Please try again later.", :rate_limited, details: body)
else
raise Error.new(
"Sophtron API request failed: #{response.code} #{response.message} - #{body}",
:fetch_failed,
details: body
)
end
rescue JSON::ParserError => e
raise Error.new("Invalid JSON response from Sophtron API: #{e.message}", :invalid_response, details: body)
endView on GitHub (pinned to e69894adb9)
Solutions
- Read the body in the message/details - it names the exact invalid field per Sophtron's validation
- Log and validate request parameters (IDs, dates) at the call site before invoking the client
- Reproduce the exact request with curl and the same auth header to iterate quickly on the corrected payload
- If calls that used to work now 400 after a Sophtron update, diff the current request body against their latest API docs
Example fix
# before - passing raw user input straight to the API
client.request(:post, "/Institution/AddAccount", body: {id: params[:institution_id]})
# after - validate shape before the call
inst_id = Integer(params[:institution_id], exception: false) or raise ArgumentError, "bad institution id"
client.request(:post, "/Institution/AddAccount", body: {id: inst_id}) Defensive patterns
Strategy: validation
Validate before calling
def valid_sophtron_request?(method, api_path, body) URI::HTTP === URI.parse(api_path) rescue false body.nil? || body.is_a?(Hash) end raise ArgumentError, "invalid Sophtron request" unless valid_sophtron_request?(method, path, body)
Try / catch
begin
client.request(:post, "/Institution/AddAccount", body: payload)
rescue Provider::Sophtron::Error => e
if e.error_type == :bad_request
mark_payload_invalid(payload, e.message) # message embeds Sophtron's validation body
else
raise
end
end Prevention
- Validate institution/account IDs and date formats at the call site before invoking the client
- Log the embedded response body - Sophtron names the offending field
- Add request fixtures per endpoint so parameter regressions surface in tests
When it happens
Trigger: A POST/GET with invalid parameters: malformed or unknown institution id when requesting account addition, invalid date parameters on a transaction query, a body that fails Sophtron's schema, or a job request referencing a nonexistent resource ID.
Common situations: Passing user-supplied institution or account IDs without validating them first; date strings not in the format Sophtron expects after a code change; Sophtron tightening request validation in an API update so previously accepted calls now 400.
Related errors
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/1a51300a0d53eb90.
Report an issue: GitHub.