phacility/phabricator · error · Exception
RRULE INTERVAL "%s" is invalid: interval must be an integer.
Error message
RRULE INTERVAL "%s" is invalid: interval must be an integer.
What it means
setInterval() requires a genuine PHP int (checked with is_int()). Numeric strings like '2' and floats like 2.0 throw even though they look numeric. The dictionary path (newFromDictionary) casts to int during normalization, so this error indicates direct setter use with an uncast value.
Source
Thrown at src/applications/calendar/parser/data/PhutilCalendarRecurrenceRule.php:411
}
$this->frequency = $frequency;
$this->frequencyScale = $map[$frequency];
return $this;
}
public function getFrequency() {
return $this->frequency;
}
public function getFrequencyScale() {
return $this->frequencyScale;
}
public function setInterval($interval) {
if (!is_int($interval)) {
throw new Exception(
pht(
'RRULE INTERVAL "%s" is invalid: interval must be an integer.',
$interval));
}
if ($interval < 1) {
throw new Exception(
pht(
'RRULE INTERVAL "%s" is invalid: interval must be 1 or more.',
$interval));
}
$this->interval = $interval;
return $this;
}
public function getInterval() {
return $this->interval;View on GitHub (pinned to 5720a38cfe)
Solutions
- Cast before calling: setInterval((int)$interval).
- Prefer newFromDictionary() for external data - it performs the cast for you.
- Validate the range too: a cast '2' passes, but 0 or negative then throws the follow-up 'must be 1 or more' error.
Example fix
// before $rule->setInterval($raw['interval']); // '2' from JSON // after $rule->setInterval((int)$raw['interval']);
Defensive patterns
Strategy: type-guard
Validate before calling
$interval = idx($dict, 'INTERVAL', 1);
if (!is_int($interval)) {
$dict['INTERVAL'] = (int)$interval; // explicit cast before it reaches setInterval()
}
// Prefer newFromDictionary($dict): its normalization performs this cast for you. Type guard
function isIntegerInterval($interval) {
return is_int($interval);
} Prevention
- Cast values from JSON/storage/request input to int before calling setters.
- Route external data through newFromDictionary() rather than individual setters.
- Watch out for floats: is_int(2.0) is false; use (int) first.
When it happens
Trigger: setInterval('2'); setInterval(2.0); values fetched from JSON, databases, or request params, which arrive as strings.
Common situations: Round-tripping rules through JSON/storage and rehydrating without casting; mixed type flows where the same value sometimes comes from the parser (int) and sometimes from raw input (string).
Related errors
- Unexpected value "%s" in "%s" RULE property: expected an int
- RRULE INTERVAL "%s" is invalid: interval must be 1 or more.
- RRULE dictionary includes unknown key "%s". Expected keys ar
- Unexpected value "%s" in "%s" RRULE property: expected only
- Weekday "%s" is not a valid weekday constant. Valid constant
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/ce492ed5e08c5f97.
Report an issue: GitHub.