{"record":{"id":"7788d8ed3f1c9198","repo":"we-promise/sure","slug":"key-must-be-an-iso-8601-date-7788d8","errorCode":null,"errorMessage":"#{key} must be an ISO 8601 date","messagePattern":"#(.+?) must be an ISO 8601 date","errorType":"validation","errorClass":"Api::V1::TransferDecisionFiltering::InvalidFilterError","httpStatus":422,"severity":"warning","filePath":"app/controllers/concerns/api/v1/transfer_decision_filtering.rb","lineNumber":90,"sourceCode":"        .where(entries: { account_id: accessible_account_ids.where(id: account_id) })\n        .select(:id)\n    end\n\n    def transfer_date_transaction_ids\n      query = accessible_transactions\n      query = query.where(\"entries.date >= ?\", parse_date_param(:start_date)) if params[:start_date].present?\n      query = query.where(\"entries.date <= ?\", parse_date_param(:end_date)) if params[:end_date].present?\n      query.select(:id)\n    end\n\n    def parse_date_param(key)\n      Date.iso8601(params[key].to_s)\n    rescue ArgumentError\n      invalid_filter!(\"#{key} must be an ISO 8601 date\")\n    end\n\n    def invalid_filter!(message)\n      raise InvalidFilterError, message\n    end\nend\n","sourceCodeStart":72,"sourceCodeEnd":93,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/controllers/concerns/api/v1/transfer_decision_filtering.rb#L72-L93","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Send start_date/end_date as strict YYYY-MM-DD on /transfers and /rejected_transfers","Use a single date normalization helper across all list endpoints","Validate with Date.iso8601 client-side to match server strictness","On 422, check the message for which key failed before retrying"],"exampleFix":"# before\nGET /api/v1/transfers?start_date=Jan 31, 2024\n# after\nGET /api/v1/transfers?start_date=2024-01-31","handlingStrategy":"validation","validationCode":"require 'date'\n%i[start_date end_date].each do |k|\n  next if filters[k].to_s.strip.empty?\n  Date.iso8601(filters[k]) # strict YYYY-MM-DD or raise\nend","typeGuard":"def valid_iso_date?(v) = v.to_s.match?(/\\A\\d{4}-\\d{2}-\\d{2}\\z/)","tryCatchPattern":"begin\n  client.get('/api/v1/transfers', filters)\nrescue Faraday::UnprocessableEntity => e\n  # 422 — body message says '<key> must be an ISO 8601 date'\nend","preventionTips":["Feed every date-filtered endpoint the same YYYY-MM-DD output","Do not pass spreadsheet-formatted dates through unchecked","Log the failing key from the 422 body to pinpoint the param"],"tags":["rails","query-params","validation","http-422","iso8601","date","concern"],"backgroundTag":"invalid-date-format","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}