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
- Fix the impossible constraint (e.g. change BYMONTHDAY=30 in February to a day that exists)
- If the rule legitimately matches rarely, verify it with a small result limit and a bounded date range before trusting it
- 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
- Always evaluate imported rules with a small result limit inside a try/catch before accepting them
- Warn users when constraint combinations are suspicious (day >= 29 in short months, BYYEARDAY=366 without leap years)
- Treat the 100-year guard as a backstop, not validation — catch it and report upstream
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
- RRULE BYDAY value "%s" has an offset with magnitude "%s", bu
- RRULE specifies BYMONTHDAY with FREQ set to WEEKLY, which vi
- RRULE specifies BYYEARDAY with FREQ of DAILY, WEEKLY or MONT
- RRULE specifies BYSETPOS with FREQ "%s", but this is invalid
- Value "%s" in RRULE "%s" parameter is invalid: it must be be
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/301495cd8492498f.
Report an issue: GitHub.