instructure/canvas-lms · warning · RruleValidationError
INTERVAL must be > 0
Error message
INTERVAL must be > 0
What it means
After confirming INTERVAL exists, rrule_validate_common_opts requires it to coerce to a positive integer; INTERVAL=0 or non-numeric raises RruleValidationError 'INTERVAL must be > 0'. Like the other RRULE validation errors, rrule_to_natural_language rescues it, logs, and returns nil.
Solutions
- Correct the stored rrule INTERVAL to >= 1.
- Sanitize at write/import time: reject or clamp INTERVAL < 1 before persisting.
- Validate the rrule string with a regex/model validation on CalendarEvent create/update.
- Rescue RruleValidationError upstream and fall back to a generic recurrence label.
Example fix
// before rrule = 'RRULE:FREQ=WEEKLY;INTERVAL=0;COUNT=4' // after rrule = 'RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=4' # clamp: [interval, 1].max
Defensive patterns
Strategy: validation
Validate before calling
interval = rropts['INTERVAL'].to_i raise ArgumentError, 'INTERVAL must be > 0' unless interval > 0
Try / catch
begin
desc = rrule_to_natural_language(rrule)
rescue RruleValidationError => e
logger.warn("rrule skipped: #{e.message}")
desc = nil
end Prevention
- Clamp INTERVAL to >= 1 whenever writing RRULE strings
- Validate RRULE syntax on CalendarEvent save
- Sanitize INTERVAL on import from external ICS feeds
When it happens
Trigger: calendar_event_json rendering for an event with rrule like 'RRULE:FREQ=DAILY;INTERVAL=0;COUNT=5' or a non-numeric INTERVAL (e.g. 'INTERVAL=abc' from corrupted import data).
Common situations: Bad hand-edited rrule values; importers writing RFC-invalid INTERVALs (RFC requires >= 1); data corruption/migration bugs zeroing the interval.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/713c42be7b5fe757.
Report an issue: GitHub.
Appendix: source
Thrown at app/helpers/rrule_helper.rb:57
when "MONTHLY"
parse_monthly(rropts)
when "YEARLY"
parse_yearly(rropts)
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
privateView on GitHub (pinned to 1c9f0bb801)