phacility/phabricator · error · Exception

RRULE evaluation failed to generate more events in the next

Error message

RRULE evaluation failed to generate more events in the next 100 years. This RRULE is likely invalid or degenerate.

What it means

This is the engine's infinite-loop guard: while advancing the year cursor to generate occurrences, more than 100 years elapsed past the rule's base year without a single event being produced. It means the rule's constraints can never be satisfied (a degenerate rule), for example BYMONTH=2 combined with BYMONTHDAY=30 since February 30th never exists.

Source

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

    $this->stateWeek = array_pop($this->setWeeks);
  }

  protected function nextYear() {
    $this->stateYear = $this->cursorYear;

    $frequency = $this->getFrequency();
    $is_yearly = ($frequency === self::FREQUENCY_YEARLY);

    if ($is_yearly) {
      $interval = $this->getInterval();
    } else {
      $interval = 1;
    }

    $this->cursorYear = $this->cursorYear + $interval;

    if ($this->cursorYear > ($this->baseYear + 100)) {
      throw new Exception(
        pht(
          'RRULE evaluation failed to generate more events in the next 100 '.
          'years. This RRULE is likely invalid or degenerate.'));
    }

  }

  private function newSecondsSet($interval, $set) {
    // TODO: This doesn't account for leap seconds. In theory, it probably
    // should, although this shouldn't impact any real events.
    $seconds_in_minute = 60;

    if ($this->cursorSecond >= $seconds_in_minute) {
      $this->cursorSecond -= $seconds_in_minute;
      return array();
    }

    list($cursor, $result) = $this->newIteratorSet(

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Fix the impossible constraint (e.g. change BYMONTHDAY=30 in February to a day that exists)
  2. If the rule legitimately matches rarely, verify it with a small result limit and a bounded date range before trusting it
  3. Wrap evaluation in a try/catch that surfaces a friendly 'this recurrence never produces events' message to the user instead of a raw exception

Example fix

// before
$rrule = 'FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=30';

// after
$rrule = 'FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=28';
Defensive patterns

Strategy: try-catch

Validate before calling

// No static check can prove satisfiability cheaply; do a bounded probe:
try {
  $probe = PhutilCalendarRecurrenceRule::newFromRRule($rrule);
  $events = id(new PhutilCalendarRecurrenceSet())
    ->setSource($probe)
    ->getEventsBetween($start, $start + phutil_units('2 years in seconds'), 1);
  if (!$events) {
    throw new Exception('Rule produced no events in a 2-year probe window.');
  }
} catch (Exception $ex) {
  throw new Exception(pht('Degenerate recurrence rule: %s', $rrule));
}

Try / catch

try {
  $events = $rule->getEvents();
} catch (Exception $ex) {
  if (strpos($ex->getMessage(), 'next 100 years') !== false) {
    // Rule never matches: reject the user's input with a friendly message.
    throw new Exception(pht('This recurrence never produces any events.'));
  }
  throw $ex;
}

Prevention

When it happens

Trigger: RRULEs with impossible constraint intersections, e.g. 'FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=30', 'FREQ=YEARLY;BYYEARDAY=366' evaluated only across non-leap years, or rules whose COUNT/UNTIL/WKST interplay filters out every candidate occurrence.

Common situations: User-authored recurring events with contradictory filters; imports from tools that emit unsatisfiable rules; rules that only match extremely rare dates (Feb 29 with strict yearly frequency) hitting the 100-year horizon before matching.

Related errors


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