we-promise/sure · error · ArgumentError
Brex transaction missing required field 'id'
Error message
Brex transaction missing required field 'id'
What it means
Raised by BrexEntry::Processor#external_id (ArgumentError) when the Brex transaction payload's :id is nil or blank. The id is mandatory because it builds the deduplication key "brex_#{id}" passed to import_transaction. process() logs it and re-raises, so one malformed transaction aborts the sync batch unless the caller filters it.
Source
Thrown at app/models/brex_entry/processor.rb:62
private
attr_reader :brex_transaction, :brex_account
def import_adapter
@import_adapter ||= Account::ProviderImportAdapter.new(account)
end
def account
@account ||= brex_account.current_account
end
def data
@data ||= brex_transaction.with_indifferent_access
end
def external_id
id = data[:id].presence
raise ArgumentError, "Brex transaction missing required field 'id'" unless id
"brex_#{id}"
end
def safe_external_id
external_id
rescue ArgumentError
"brex_unknown"
end
def name
data[:description].presence ||
merchant_payload[:raw_descriptor].presence ||
merchant_payload[:name].presence ||
I18n.t("brex_items.entries.default_name")
end
def notesView on GitHub (pinned to e69894adb9)
Solutions
- Inspect the failing payload (data) and confirm the id key — log data.keys for the failing transaction to catch shape drift immediately.
- Filter before processing: skip (and log) entries whose [:id] is blank so one bad record cannot kill the batch.
- If the shape changed upstream (renamed/nested field), update the extraction in BrexEntry::Processor or map it before enqueueing.
- Fix fixtures/tests to always include a realistic Brex transaction id.
Example fix
# before
transactions.each { |tx| BrexEntry::Processor.new(tx, brex_account: ba).process }
# after
transactions.each do |tx|
unless tx.with_indifferent_access[:id].present?
Rails.logger.warn("Skipping Brex transaction without id: #{tx.inspect}")
next
end
BrexEntry::Processor.new(tx, brex_account: ba).process
end Defensive patterns
Strategy: validation
Validate before calling
tx = transaction_payload.with_indifferent_access return :skipped unless tx[:id].present? # every Brex transaction must carry an id
Type guard
# Ruby def processable_brex_tx?(payload) payload.is_a?(Hash) && payload.with_indifferent_access[:id].present? end
Try / catch
begin
BrexEntry::Processor.new(tx, brex_account: ba).process
rescue ArgumentError => e
raise unless e.message.include?("missing required field 'id'")
Rails.logger.warn("Skipping Brex transaction without id: #{tx.inspect}")
:skipped
end Prevention
- Validate the id field at the queue boundary (webhook/importer entry) so malformed payloads are quarantined before processing.
- Keep fixtures and VCR cassettes shaped like real Brex payloads, id included.
- When Brex ships API changes, log data.keys on failures to catch renamed/nested id fields fast.
When it happens
Trigger: BinanceItem::Importer-style loop hands the processor a transaction hash lacking "id" — e.g. a Brex webhook body or test fixture shaped differently, an upstream API change renaming the field, an empty-string id, or a payload accidentally wrapped one level too deep (data[:id] nil because the hash is nested under "transaction").
Common situations: VCR fixtures recorded from a different API version; sandbox payloads with null ids; a payload-shape refactor upstream; JSON where the array element is { "transaction" => {...} } rather than the transaction itself.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- Unable to parse transaction date: #{date_value.inspect}
- bad_request
- unauthorized
- access_forbidden
- not_found
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/4e3f759c1872d675.
Report an issue: GitHub.