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

not_found

not_found

Error message

Brex resource not found

What it means

Raised by Provider::Brex#handle_response on HTTP 404: the Brex resource referenced by the request does not exist. In practice this almost always means the account id passed to get_cash_transactions was deleted (or never existed) at Brex, since paths are built from ids returned earlier by get_accounts. http_status 404 and trace_id are attached.

Source

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

    def handle_response(response, path:)
      trace_id = brex_trace_id(response)

      case response.code
      when 200
        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

View on GitHub (pinned to e69894adb9)

Solutions

  1. Re-run client.get_accounts and verify the account id still appears; if gone, mark the local account closed/inactive instead of retrying
  2. Verify the id came from Brex's own accounts response (ids are Brex-generated, not user names)
  3. Check environment consistency (staging ids against production base_url 404)
  4. Keep the trace_id if you need to ask Brex support about a resource you believe should exist

Example fix

# before
transactions = client.get_cash_transactions(account.brex_account_id)

# after
begin
  transactions = client.get_cash_transactions(account.brex_account_id)
rescue Provider::Brex::BrexError => e
  raise unless e.error_type == :not_found
  account.update!(status: "closed", active: false)
  transactions = { transactions: [] }
end
Defensive patterns

Strategy: fallback

Validate before calling

def brex_account_still_listed?(client, account_id)
  client.get_accounts[:accounts].any? { |a| a.with_indifferent_access[:id] == account_id }
rescue Provider::Brex::BrexError
  false
end

Type guard

def brex_not_found?(error)
  error.is_a?(Provider::Brex::BrexError) && error.error_type == :not_found
end

Try / catch

begin
  client.get_cash_transactions(account_id)
rescue Provider::Brex::BrexError => e
  raise unless e.error_type == :not_found
  account.update!(status: "closed", active: false) # degrade gracefully, no retry
  { transactions: [] }
end

Prevention

When it happens

Trigger: get_cash_transactions(account_id, ...) where the account was closed/deleted at Brex after the last account-list sync; a stale or wrong account id reaching the client; querying a staging resource that only exists in production.

Common situations: Users closing Brex accounts between syncs while the local Account record persists; holding ids from an old environment; manually entered ids.

Related errors


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