we-promise/sure · warning · Api::V1::SecurityResourceFiltering::InvalidFilterError
#{key} must be an ISO 8601 date
Error message
#{key} must be an ISO 8601 date What it means
Api::V1::SecurityResourceFiltering (app/controllers/concerns/api/v1/security_resource_filtering.rb:47-52) supplies parse_date_param to the securities and security_prices index actions. It uses strict Date.iso8601; failures raise ArgumentError, converted by invalid_filter! into InvalidFilterError '<key> must be an ISO 8601 date', which each controller rescues to 422 validation_failed.
Source
Thrown at app/controllers/concerns/api/v1/security_resource_filtering.rb:51
end
def parse_boolean_filter_param(key)
normalized_value = params[key].to_s.strip.downcase
invalid_filter!("#{key} must be true or false") if normalized_value.blank?
return BOOLEAN_FILTERS.fetch(normalized_value) if BOOLEAN_FILTERS.key?(normalized_value)
invalid_filter!("#{key} must be true or false")
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
- Send date filters as strict YYYY-MM-DD on /securities and /security_prices
- Centralize one date-formatting helper that always emits ISO 8601 dates
- Validate with Date.iso8601 client-side before the request
- Read the 422 message — it names the exact failing param
Example fix
# before GET /api/v1/securities?start_date=31-01-2024 # after GET /api/v1/securities?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/securities', filters)
rescue Faraday::UnprocessableEntity => e
# 422 — body message says '<key> must be an ISO 8601 date'
end Prevention
- One date-format helper for every list endpoint
- Normalize locale formats at the client boundary
- Test filter formatting with non-padded dates — they must fail fast client-side
When it happens
Trigger: GET /api/v1/securities?start_date=2024/01/31 or GET /api/v1/security_prices?end_date=Jan 31 — any date filter on those endpoints that is not strict YYYY-MM-DD.
Common situations: Shared client code sending US or slash-formatted dates to every index endpoint uniformly; spreadsheet-exported dates with locale formatting; timestamps reused from holdings' more lenient Date.parse behavior.
Related errors
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/fcb992fc84965cba.
Report an issue: GitHub.