instructure/canvas-lms · error · RruleValidationError
Unsupported BYMONTHDAY, only a single day is permitted.
Error message
Unsupported BYMONTHDAY, only a single day is permitted.
What it means
Raised by the generic validation guard in parse_bymonthday when parsing a yearly RRULE's BYMONTHDAY part: Canvas only supports a single month day (e.g. '15'), so the input at fault is a comma-separated BYMONTHDAY list (e.g. '1,15') supplied by the calendar/RRULE payload.
Solutions
- Use a single BYMONTHDAY value, e.g. BYMONTHDAY=15
- Model multiple days as multiple separate recurring calendar events (one per day)
- Reject or split multi-day rules at the API boundary with a clear client-facing message
Example fix
// before "FREQ=YEARLY;INTERVAL=1;BYMONTHDAY=1,15" // after "FREQ=YEARLY;INTERVAL=1;BYMONTHDAY=15"
Defensive patterns
Strategy: validation
Validate before calling
raise ArgumentError, "only a single BYMONTHDAY is supported" unless bymonthday.split(",").length == 1 Try / catch
begin
RruleHelper.rrule_to_natural_language(rropts)
rescue RruleValidationError => e
render json: { errors: [e.message] }, status: :bad_request
end Prevention
- Model multi-day yearly recurrences as separate events
- Restrict yearly recurrence pickers to a single day
- Handle the error explicitly and inform users of the platform limitation
When it happens
Trigger: Calling rrule_to_natural_language with a yearly RRULE whose BYMONTHDAY contains a comma-separated list, e.g. BYMONTHDAY=1,15 — any value where split(",").length != 1.
Common situations: Clients copying RFC-5545 examples that legally allow lists (BYMONTHDAY=1,15) and expecting Canvas to support them; UIs allowing multi-select of days; importing ICS files with multi-day yearly rules.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Invalid BYMONTHDAY
- A yearly RRULE must include BYDAY or BYMONTHDAY
- COUNT must be > 0
- COUNT must be <=
- Invalid BYDAY
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/81d9f0ab36f21764.
Report an issue: GitHub.
Appendix: source
Thrown at app/helpers/rrule_helper.rb:138
match = /\A([-+]?\d+)?([A-Z]{2})\z/.match(d)
raise RruleValidationError, I18n.t("Invalid BYDAY '%{byday}'", byday:) unless match
{
occurrence: match[1].to_i,
day_of_week: DAYS_OF_WEEK[match[2]]
}
end
end
def parse_bymonth(bymonth)
month = bymonth.to_i
raise RruleValidationError, I18n.t("Invalid BYMONTH '%{bymonth}'", bymonth:) unless month.between?(1, 12)
month
end
def parse_bymonthday(bymonthday, month)
raise RruleValidationError, I18n.t("Unsupported BYMONTHDAY, only a single day is permitted.") unless bymonthday.split(",").length == 1
monthday = bymonthday.to_i
# not validating if we're in a leap year
raise RruleValidationError, I18n.t("Invalid BYMONTHDAY '%{bymonthday}'", bymonthday:) unless monthday.between?(1, DAYS_IN_MONTH[month])
monthday
end
def format_date(date_str)
date = date_str.split("T")[0]
year = date[0, 4].to_i
month = date[4, 2].to_i
day = date[6, 2].to_i
I18n.l(Date.new(year, month, day), format: :medium)
end
View on GitHub (pinned to 1c9f0bb801)