we-promise/sure · warning · Api::V1::TransferDecisionFiltering::InvalidFilterError

#{key} must be an ISO 8601 date

Error message

#{key} must be an ISO 8601 date

What it means

Api::V1::TransferDecisionFiltering (app/controllers/concerns/api/v1/transfer_decision_filtering.rb:86-92) supplies parse_date_param for the transfers and rejected_transfers index actions, filtering on entries.date with start_date/end_date. Dates must pass strict Date.iso8601; failures are converted by invalid_filter! into InvalidFilterError '<key> must be an ISO 8601 date' and rescued to 422 validation_failed in each controller.

Source

Thrown at app/controllers/concerns/api/v1/transfer_decision_filtering.rb:90

        .where(entries: { account_id: accessible_account_ids.where(id: account_id) })
        .select(:id)
    end

    def transfer_date_transaction_ids
      query = accessible_transactions
      query = query.where("entries.date >= ?", parse_date_param(:start_date)) if params[:start_date].present?
      query = query.where("entries.date <= ?", parse_date_param(:end_date)) if params[:end_date].present?
      query.select(:id)
    end

    def parse_date_param(key)
      Date.iso8601(params[key].to_s)
    rescue ArgumentError
      invalid_filter!("#{key} must be an ISO 8601 date")
    end

    def invalid_filter!(message)
      raise InvalidFilterError, message
    end
end

View on GitHub (pinned to e69894adb9)

Solutions

  1. Send start_date/end_date as strict YYYY-MM-DD on /transfers and /rejected_transfers
  2. Use a single date normalization helper across all list endpoints
  3. Validate with Date.iso8601 client-side to match server strictness
  4. On 422, check the message for which key failed before retrying

Example fix

# before
GET /api/v1/transfers?start_date=Jan 31, 2024
# after
GET /api/v1/transfers?start_date=2024-01-31
Defensive patterns

Strategy: validation

Validate before calling

require 'date'
%i[start_date end_date].each do |k|
  next if filters[k].to_s.strip.empty?
  Date.iso8601(filters[k]) # strict YYYY-MM-DD or raise
end

Type guard

def valid_iso_date?(v) = v.to_s.match?(/\A\d{4}-\d{2}-\d{2}\z/)

Try / catch

begin
  client.get('/api/v1/transfers', filters)
rescue Faraday::UnprocessableEntity => e
  # 422 — body message says '<key> must be an ISO 8601 date'
end

Prevention

When it happens

Trigger: GET /api/v1/transfers?start_date=2024.01.31 or GET /api/v1/rejected_transfers?end_date=12/31/2024 — any date filter on those two endpoints that is not strict YYYY-MM-DD.

Common situations: One shared date-picker component feeding multiple endpoints while only some are strict; dotted or slashed formats from exports; non-padded dates built by hand.

Related errors


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