instructure/canvas-lms · warning · RruleValidationError

Missing INTERVAL

Error message

Missing INTERVAL

What it means

rrule_validate_common_opts requires an INTERVAL key in the parsed RRULE options before computing a natural-language description; without it, RruleValidationError 'Missing INTERVAL' is raised (then logged and swallowed to nil by rrule_to_natural_language's rescue).

Solutions

  1. Default INTERVAL to 1 when absent before calling the helper: rropts['INTERVAL'] ||= 1.
  2. Fix the data: rewrite stored rrule strings to include INTERVAL.
  3. Normalize at import time so all stored RRULEs carry explicit INTERVAL.
  4. Rescue RruleValidationError in the JSON rendering and omit the natural-language field gracefully.

Example fix

// before
rropts = RruleHelper.rrule_parse(event.rrule)
desc = helper.rrule_to_natural_language(event.rrule)
// after
rropts = RruleHelper.rrule_parse(event.rrule)
rropts['INTERVAL'] ||= '1'
desc = helper.rrule_to_natural_language(event.rrule)
Defensive patterns

Strategy: validation

Validate before calling

rropts['INTERVAL'] ||= '1'
raise ArgumentError, 'missing INTERVAL' unless rropts.key?('INTERVAL')

Try / catch

begin
  desc = rrule_to_natural_language(rrule)
rescue RruleValidationError
  desc = nil
end

Prevention

When it happens

Trigger: Rendering calendar_event_json for an event whose rrule string omits INTERVAL, e.g. 'RRULE:FREQ=DAILY;COUNT=5' (RFC 5545 makes INTERVAL default 1, so producers often omit it).

Common situations: ICS imports from producers that legally omit INTERVAL; hand-authored rrule strings in seeds/tests; legacy rows written before validation existed.

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


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/5982cbe19e545bb4. Report an issue: GitHub.

Appendix: source

Thrown at app/helpers/rrule_helper.rb:56

      parse_weekly(rropts)
    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

View on GitHub (pinned to 1c9f0bb801)