we-promise/sure · warning · ArgumentError
validation_failed
validation_failed
Error message
Invalid #{param_name} format What it means
HoldingsController#parse_date! (app/controllers/api/v1/holdings_controller.rb:97-100) wraps Ruby's lenient Date.parse for the date, start_date and end_date query params. When the value cannot be parsed, Ruby raises Date::Error/ArgumentError/TypeError and the controller re-raises ArgumentError with 'Invalid <param> format'. The index action rescues ArgumentError and renders 422 validation_failed with the message in both message and errors.
Source
Thrown at app/controllers/api/v1/holdings_controller.rb:100
def safe_page_param
page = params[:page].to_i
page > 0 ? page : 1
end
def safe_per_page_param
per_page = params[:per_page].to_i
case per_page
when 1..100
per_page
else
25
end
end
def parse_date!(value, param_name)
Date.parse(value)
rescue Date::Error, ArgumentError, TypeError
raise ArgumentError, "Invalid #{param_name} format"
end
def render_validation_error(message, errors)
render json: {
error: "validation_failed",
message: message,
errors: errors
}, status: :unprocessable_entity
end
def log_and_render_error(action, exception)
Rails.logger.error "HoldingsController##{action} error: #{exception.message}"
Rails.logger.error exception.backtrace.join("\n")
render json: {
error: "internal_server_error",
message: "An unexpected error occurred"
}, status: :internal_server_error
endView on GitHub (pinned to e69894adb9)
Solutions
- Send dates as strict ISO 8601 YYYY-MM-DD (e.g. 2024-01-31)
- Check every date param (date, start_date, end_date) is well-formed before the request
- URL-encode values and strip stray whitespace/quotes
- Prefer explicit formats: '2024-01-31' never '31/01/2024' since Date.parse is ambiguous, not strict
Example fix
# before GET /api/v1/holdings?start_date=01/31/2024 # after GET /api/v1/holdings?start_date=2024-01-31
Defensive patterns
Strategy: validation
Validate before calling
require 'date' %i[date start_date end_date].each do |k| next if params[k].to_s.strip.empty? Date.iso8601(params[k]) # raises Date::Error unless YYYY-MM-DD end
Type guard
def valid_iso_date?(v) = v.to_s.match?(/\A\d{4}-\d{2}-\d{2}\z/) && !!Date.iso8601(v) rescue false Try / catch
begin
client.get('/api/v1/holdings', params)
rescue Faraday::UnprocessableEntity => e
# 422 validation_failed: e.response[:body]['errors'] lists 'Invalid <param> format'
end Prevention
- Always emit YYYY-MM-DD from one shared formatter
- Never send locale-formatted dates (MM/DD/YYYY) — Date.parse may misread them silently
- Strip whitespace before sending query params
When it happens
Trigger: GET /api/v1/holdings?date=not-a-date, ?start_date=2024-13-01 (month 13), or any non-date string for date/start_date/end_date. Empty values are skipped because of the .present? guard, so only malformed non-empty values trigger it.
Common situations: Sending locale-specific formats like '31/01/2024' or 'Jan 31, 2024' — note Date.parse may silently 'succeed' with the wrong interpretation for ambiguous inputs, which is worse than the error; passing a datetime string where only the date part is wanted; copy/paste artifacts like quotes or trailing spaces in the URL.
Related errors
- validation_failed
- validation_failed
- #{key} must be an ISO 8601 date
- #{key} must be an ISO 8601 date
- validation_error
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/5026d0b9fb56563d.
Report an issue: GitHub.