we-promise/sure · error · ArgumentError

Unable to parse transaction date: #{date_value.inspect}

Error message

Unable to parse transaction date: #{date_value.inspect}

What it means

Raised by BrexEntry::Processor#date (ArgumentError) when posted_at_date/initiated_at_date cannot be converted to a Date: a String that Time.parse/Date.parse rejects, or a type hitting the else branch (nil, Hash, Array). The original error is logged ('Failed to parse Brex transaction date ...') and re-raised as this uniform message including value.inspect.

Source

Thrown at app/models/brex_entry/processor.rb:165

      case date_value
      when String
        if date_value.include?("T") || date_value.include?(":")
          Time.parse(date_value).in_time_zone(account&.family&.timezone).to_date
        else
          Date.parse(date_value)
        end
      when Integer, Float
        Time.at(date_value).in_time_zone(account&.family&.timezone).to_date
      when Time, DateTime
        date_value.in_time_zone(account&.family&.timezone).to_date
      when Date
        date_value
      else
        raise ArgumentError, "Invalid date format: #{date_value.inspect}"
      end
    rescue ArgumentError, TypeError => e
      Rails.logger.error("Failed to parse Brex transaction date '#{date_value}': #{e.message}")
      raise ArgumentError, "Unable to parse transaction date: #{date_value.inspect}"
    end

    def extra
      {
        brex: {
          transaction_id: data[:id],
          account_kind: brex_account.account_kind,
          type: data[:type],
          card_id: data[:card_id],
          transfer_id: data[:transfer_id],
          expense_id: data[:expense_id],
          card_transaction_operation_reference_id: data[:card_transaction_operation_reference_id],
          initiated_at_date: data[:initiated_at_date],
          posted_at_date: data[:posted_at_date],
          merchant: BrexAccount.sanitize_payload(data[:merchant])
        }.compact
      }
    end

View on GitHub (pinned to e69894adb9)

Solutions

  1. Log the inspected value (already logged) and check the payload — most cases are a nil pair or a renamed/nested date field from Brex.
  2. Pre-validate in the importer: parse the date yourself and skip/quarantine records whose date fields are missing or unparseable, rather than aborting the whole batch.
  3. If pending transactions legitimately lack posted dates, default them (e.g. to initiated_at_date or Date.current) upstream of the processor.
  4. Pin explicit formats: prefer Date.strptime(value, '%Y-%m-%d') for ISO dates instead of Date.parse ambiguity.

Example fix

# before
BrexEntry::Processor.new(tx, brex_account: ba).process

# after — quarantine unparseable dates before the processor sees them
date_value = tx.with_indifferent_access[:posted_at_date].presence || tx.with_indifferent_access[:initiated_at_date].presence
begin
  Date.parse(date_value) if date_value.is_a?(String)
rescue ArgumentError, TypeError
  Rails.logger.warn("Quarantining Brex tx with bad date: #{date_value.inspect}")
  next
end
BrexEntry::Processor.new(tx, brex_account: ba).process
Defensive patterns

Strategy: validation

Validate before calling

def parseable_brex_date?(value)
  case value
  when String then begin; Date.parse(value); true; rescue ArgumentError; false; end
  when Integer, Float, Time, DateTime, Date then true
  else false # nil, Hash, Array will raise in the processor
  end
end

Type guard

# Ruby
def valid_brex_date_payload?(payload)
  %w[posted_at_date initiated_at_date].any? do |k|
    v = payload.with_indifferent_access[k]
    v.present? && parseable_brex_date?(v)
  end
end

Try / catch

begin
  processor.process
rescue ArgumentError => e
  raise unless e.message.include?("Unable to parse transaction date")
  Rails.logger.warn("Quarantining transaction with unparseable date: #{tx.inspect}")
  :skipped
end

Prevention

When it happens

Trigger: data[:posted_at_date] is "2026-13-01" or "not-a-date" (Date.parse raises); both posted_at_date and initiated_at_date are nil (presence || presence → nil → else branch raises 'Invalid date format: nil'); the date arrives as a Hash (e.g. { "date" => "..." }) or an unexpected object type.

Common situations: Upstream schema change where dates became nested objects; transactions in an unusual state (pending with no timestamps) yielding nil dates; locale-dependent strings like "31/12/2026" that Time.parse misreads or rejects depending on Date._parse behavior.

Understand the failure class

Related errors


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