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)
    end

View on GitHub (pinned to e69894adb9)

Solutions

  1. Read the body in the message/details - it names the exact invalid field per Sophtron's validation
  2. Log and validate request parameters (IDs, dates) at the call site before invoking the client
  3. Reproduce the exact request with curl and the same auth header to iterate quickly on the corrected payload
  4. 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

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.