instructure/canvas-lms · error · RruleValidationError
Missing COUNT or UNTIL
Error message
Missing COUNT or UNTIL
What it means
RruleHelper validates recurring-event RRULE options before converting them to natural language. Canvas does not support never-ending event series because every event in the series must be materialized in the database to support the paginated calendar_events API, so an RRULE must terminate via COUNT or UNTIL. If the rropts hash contains neither key, rrule_validate_common_opts raises RruleValidationError with this message.
Solutions
- Add a COUNT (number of occurrences) or UNTIL (end date) clause to the RRULE so the series terminates
- If the series is meant to be infinite, split it into bounded segments (e.g. COUNT=365 chunks) since Canvas caps series via RruleHelper::RECURRING_EVENT_LIMIT
- Validate the RRULE before saving the event and return a 400 to the client explaining that recurring events must have an end
Example fix
// before "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO" // after "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO;COUNT=10"
Defensive patterns
Strategy: validation
Validate before calling
def valid_rrule_termination?(rropts)
rropts.key?("COUNT") || rropts.key?("UNTIL")
end
raise ArgumentError, "RRULE needs COUNT or UNTIL" unless valid_rrule_termination?(rropts) Try / catch
begin
RruleHelper.rrule_to_natural_language(rropts)
rescue RruleValidationError => e
render json: { errors: [e.message] }, status: :bad_request
end Prevention
- Always emit COUNT or UNTIL when building RRULEs
- Treat infinite recurrence as unsupported in Canvas
- Validate RRULE strings at the API boundary before persistence
When it happens
Trigger: Calling RruleHelper.rrule_to_natural_language with an rropts hash that has FREQ (and valid INTERVAL) but omits both the "COUNT" and "UNTIL" keys — e.g. an RRULE string like FREQ=DAILY;INTERVAL=1 with no termination clause.
Common situations: Importing or parsing external calendar data (ICS files) whose RRULEs omit COUNT/UNTIL because they were designed as infinite series; clients constructing recurring calendar events via the API and forgetting the end condition; upstream calendar libraries that allow open-ended recurrence.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- A yearly RRULE must include BYDAY or BYMONTHDAY
- COUNT must be > 0
- COUNT must be <=
- Invalid BYDAY
- Invalid BYMONTH
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/858ea36c896a22cf.
Report an issue: GitHub.
Appendix: source
Thrown at app/helpers/rrule_helper.rb:61
else
raise RruleValidationError, I18n.t("Invalid FREQ '%{freq}'", freq: rropts["FREQ"])
end
rescue => e
logger.error "RRULE to natural language failure: #{e}"
nil
end
def rrule_parse(rrule)
Hash[*rrule.sub(/^RRULE:/, "").split(/[;=]/)]
end
def rrule_validate_common_opts(rropts)
raise RruleValidationError, I18n.t("Missing INTERVAL") unless rropts.key?("INTERVAL")
raise RruleValidationError, I18n.t("INTERVAL must be > 0") unless rropts["INTERVAL"].to_i > 0
# We do not support never ending series because each event in the series
# must get created in the db to support the paginated calendar_events api
raise RruleValidationError, I18n.t("Missing COUNT or UNTIL") unless rropts.key?("COUNT") || rropts.key?("UNTIL")
if rropts.key?("COUNT")
raise RruleValidationError, I18n.t("COUNT must be > 0") unless rropts["COUNT"].to_i > 0
raise RruleValidationError, I18n.t("COUNT must be <= %{limit}", limit: RruleHelper::RECURRING_EVENT_LIMIT) unless rropts["COUNT"].to_i <= RruleHelper::RECURRING_EVENT_LIMIT
else
begin
format_date(rropts["UNTIL"])
rescue
raise RruleValidationError, I18n.t("Invalid UNTIL '%{until_date}'", until_date: rropts["UNTIL"])
end
end
end
private
DAYS_OF_WEEK = {
"SU" => I18n.t("Sun"),
"MO" => I18n.t("Mon"),View on GitHub (pinned to 1c9f0bb801)