instructure/canvas-lms · error · PeerReview::InvalidDatesError
Invalid date format for
Error message
Invalid date format for %{field}: %{value} What it means
PeerReview::InvalidDatesError raised by parse_date when a date field in the child dates hash is a String that Time.zone.parse cannot convert to a Time (returns nil). Unlike validate_peer_review_dates (which uses Api::ISO8601_REGEX), parse_date relies on Rails' time parser, so only strings producing nil fail here — unparseable garbage, not merely non-ISO8601 formats. Thrown from validate_dates_within_parent_boundaries during peer review vs parent date validation.
Solutions
- Send ISO8601/ISO8601-formatted UTC timestamps, e.g. '2026-05-01T00:00:00Z'
- Pre-parse strings to Time objects client-side before passing the dates hash
- Log the %{field} and %{value} in the message to find the offending key and fix the producer
- Sanitize inputs: drop blank or non-date strings before calling the validator
Example fix
// before
validate_peer_review_dates_against_parent_assignment({ due_at: 'March 3rd, 2026 sometime' }, assignment)
// after
validate_peer_review_dates_against_parent_assignment({ due_at: '2026-03-03T00:00:00Z' }, assignment) Defensive patterns
Strategy: type-guard
Validate before calling
def ensure_parseable_dates(dates)
dates.each do |field, value|
next if value.nil? || value.is_a?(Time)
raise ArgumentError, "#{field} unparseable: #{value}" if Time.zone.parse(value).nil?
end
end Type guard
def coercible_date?(v) v.is_a?(Time) || (v.is_a?(String) && !Time.zone.parse(v).nil?) end
Try / catch
begin
validator.validate_peer_review_dates_against_parent_assignment(dates, assignment)
rescue PeerReview::InvalidDatesError => e
if e.message.start_with?('Invalid date format')
bad = e.message[/value: (.+)$/, 1]
dates.reject! { |_, v| v == bad }
retry
end
raise
end Prevention
- Always transmit ISO8601 timestamps ('2026-05-01T00:00:00Z')
- Never send localized or human-formatted date strings to the API
- Coerce strings to Time objects at the edge of your integration
- Scrub placeholder values ('TBD', 'null', '') out of date fields before submission
When it happens
Trigger: Calling validate_peer_review_dates_against_parent_assignment or validate_override_dates_against_parent_override with a dates hash containing e.g. due_at: 'not-a-date', '32/13/2026', or another string Time.zone.parse cannot interpret.
Common situations: API clients sending localized date formats ('01/02/2026' ambiguity aside, some locales produce nil); empty-ish strings that pass present? but fail parsing; deserialization bugs delivering placeholder text like 'null' or 'TBD' as the date value.
Related errors
- Available from date cannot be after until date
- Due date cannot be after until date
- Due date cannot be before available from date
- Group does not exist
- Invalid parent assignment
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/a5c018745daec4bb.
Report an issue: GitHub.
Appendix: source
Thrown at app/services/peer_review/validations.rb:138
validate_peer_review_dates(peer_review_dates)
validate_dates_within_parent_boundaries(
child_dates: peer_review_dates,
parent_unlock_at: parent_assignment.unlock_at,
parent_due_at: parent_assignment.due_at,
parent_lock_at: parent_assignment.lock_at,
is_override: false
)
end
def parse_date(dates_hash, field)
date_value = dates_hash.fetch(field, nil)
return nil unless date_value.present?
if date_value.is_a?(String)
parsed = Time.zone.parse(date_value)
if parsed.nil?
raise PeerReview::InvalidDatesError,
I18n.t("Invalid date format for %{field}: %{value}", field:, value: date_value)
end
parsed
else
date_value
end
end
def validate_dates_within_parent_boundaries(child_dates:, parent_unlock_at:, parent_due_at:, parent_lock_at:, is_override: false)
child_unlock_at = parse_date(child_dates, :unlock_at)
child_due_at = parse_date(child_dates, :due_at)
child_lock_at = parse_date(child_dates, :lock_at)
# Validate: parent unlock_at <= parent due_at
if parent_unlock_at && parent_due_at && parent_unlock_at > parent_due_at
raise PeerReview::InvalidDatesError,
is_override ? I18n.t("Parent override due date cannot be before parent override available from date") : I18n.t("Assignment due date cannot be before assignment available from date")
endView on GitHub (pinned to 1c9f0bb801)