phacility/phabricator · error · Exception

RRULE specifies BYMONTHDAY with FREQ set to WEEKLY, which vi

Error message

RRULE specifies BYMONTHDAY with FREQ set to WEEKLY, which violates RFC5545.

What it means

RFC5545 states that BYMONTHDAY MUST NOT be combined with FREQ=WEEKLY, because 'day of month' has no meaning inside a weekly cycle. PhutilCalendarRecurrenceRule::resetSource() enforces this as soon as the rule starts evaluating, so any weekly rule carrying BYMONTHDAY fails fast instead of producing wrong dates.

Source

Thrown at src/applications/calendar/parser/data/PhutilCalendarRecurrenceRule.php:574

    self::getWeekdayIndex($week_start);

    $this->weekStart = $week_start;
    return $this;
  }

  public function getWeekStart() {
    return $this->weekStart;
  }

  public function resetSource() {
    $frequency = $this->getFrequency();

    if ($this->getByMonthDay()) {
      switch ($frequency) {
        case self::FREQUENCY_WEEKLY:
          // RFC5545: "The BYMONTHDAY rule part MUST NOT be specified when the
          // FREQ rule part is set to WEEKLY."
          throw new Exception(
            pht(
              'RRULE specifies BYMONTHDAY with FREQ set to WEEKLY, which '.
              'violates RFC5545.'));
          break;
        default:
          break;
      }

    }

    if ($this->getByYearDay()) {
      switch ($frequency) {
        case self::FREQUENCY_DAILY:
        case self::FREQUENCY_WEEKLY:
        case self::FREQUENCY_MONTHLY:
          // RFC5545: "The BYYEARDAY rule part MUST NOT be specified when the
          // FREQ rule part is set to DAILY, WEEKLY, or MONTHLY."
          throw new Exception(

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Remove the BYMONTHDAY part if a plain weekly recurrence is intended
  2. Switch FREQ to MONTHLY or DAILY if the day-of-month filter is actually required
  3. Pre-validate imported RRULEs: reject BYMONTHDAY whenever FREQ=WEEKLY before handing the rule to the parser

Example fix

// before
$rrule = 'FREQ=WEEKLY;BYMONTHDAY=15;BYDAY=MO';

// after
$rrule = 'FREQ=WEEKLY;BYDAY=MO';
Defensive patterns

Strategy: validation

Validate before calling

$parts = array();
foreach (explode(';', $rrule) as $part) {
  $kv = explode('=', $part, 2);
  $parts[$kv[0]] = idx($kv, 1);
}
if (idx($parts, 'FREQ') === 'WEEKLY' && isset($parts['BYMONTHDAY'])) {
  throw new Exception('BYMONTHDAY is not allowed with FREQ=WEEKLY (RFC5545).');
}

Try / catch

try {
  $rule->getEvents();
} catch (Exception $ex) {
  if (strpos($ex->getMessage(), 'BYMONTHDAY') !== false) {
    // Strip BYMONTHDAY and retry with a sanitized rule.
  }
  throw $ex;
}

Prevention

When it happens

Trigger: An RRULE like 'FREQ=WEEKLY;BYMONTHDAY=15', or building the rule in code via setFrequency(self::FREQUENCY_WEEKLY) followed by setByMonthDay(array(15)) and then calling getEvents()/resetSource().

Common situations: Machine-generated or hand-written .ics files that reuse BYMONTHDAY across frequencies; code that copies a monthly rule template and only changes FREQ to WEEKLY; calendar imports from buggy producers.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/b2cc1c44ddeb2be8. Report an issue: GitHub.