we-promise/sure · error · Provider::Brex::BrexError

fetch_failed

fetch_failed

Error message

Failed to fetch data from Brex API: HTTP #{response.code}

What it means

Raised by Provider::Brex#handle_response for any status outside 200/400/401/403/404/429 — in practice Brex-side 5xx errors (500, 502, 503, 504) or unusual intermediary codes. The message embeds the exact HTTP code and the error carries http_status plus trace_id, so 5xx incidents can be correlated with Brex support.

Source

Thrown at app/models/provider/brex.rb:227

        parse_json(response.body)
      when 400
        Rails.logger.error "Brex API: bad request for #{path} trace_id=#{trace_id}"
        raise BrexError.new("Bad request to Brex API", :bad_request, http_status: 400, trace_id: trace_id)
      when 401
        Rails.logger.warn "Brex API: unauthorized for #{path} trace_id=#{trace_id}"
        raise BrexError.new("Invalid Brex API token or account permissions", :unauthorized, http_status: 401, trace_id: trace_id)
      when 403
        Rails.logger.warn "Brex API: access forbidden for #{path} trace_id=#{trace_id}"
        raise BrexError.new("Access forbidden - check Brex API token scopes", :access_forbidden, http_status: 403, trace_id: trace_id)
      when 404
        Rails.logger.warn "Brex API: resource not found for #{path} trace_id=#{trace_id}"
        raise BrexError.new("Brex resource not found", :not_found, http_status: 404, trace_id: trace_id)
      when 429
        Rails.logger.warn "Brex API: rate limited for #{path} trace_id=#{trace_id}"
        raise BrexError.new("Brex rate limit exceeded. Please try again later.", :rate_limited, http_status: 429, trace_id: trace_id)
      else
        Rails.logger.error "Brex API: unexpected response code=#{response.code} path=#{path} trace_id=#{trace_id}"
        raise BrexError.new("Failed to fetch data from Brex API: HTTP #{response.code}", :fetch_failed, http_status: response.code, trace_id: trace_id)
      end
    end

    def parse_json(body)
      return {} if body.blank?

      JSON.parse(body, symbolize_names: true)
    end

    def rfc3339_start_date(start_date)
      time =
        case start_date
        when Time
          start_date
        when DateTime
          start_date.to_time
        when Date
          start_date.to_time(:utc)

View on GitHub (pinned to e69894adb9)

Solutions

  1. Check e.http_status on the raised BrexError — 5xx means retry after backoff; the request outcome may or may not have committed, but all Brex calls here are reads so retry is safe
  2. Check Brex status channels for an ongoing incident before burning retries
  3. Exponential backoff with a cap and let the next scheduled sync pick up if the outage lasts
  4. For repeated 5xx, collect trace_id values and report to Brex support

Example fix

# before
client.get_accounts

# after
attempts = 0
begin
  client.get_accounts
rescue Provider::Brex::BrexError => e
  raise unless e.http_status.to_i >= 500 && (attempts += 1) <= 3
  sleep(2**attempts)
  retry
end
Defensive patterns

Strategy: retry

Type guard

def brex_server_error?(error)
  error.is_a?(Provider::Brex::BrexError) && error.error_type == :fetch_failed && error.http_status.to_i >= 500
end

Try / catch

attempts = 0
begin
  client.get_accounts
rescue Provider::Brex::BrexError => e
  raise unless e.error_type == :fetch_failed && e.http_status.to_i >= 500 && (attempts += 1) <= 3
  sleep(2**attempts)
  retry
end

Prevention

When it happens

Trigger: Brex API incident returning 500/503 during a sync; gateway 502/504 when a paginated request takes too long upstream; maintenance windows answering 503.

Common situations: Provider-side outages noticed first as failed sync jobs; long backfill windows overlapping with Brex deploys.

Related errors


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