phacility/phabricator · error · Exception

Value "%s" in RRULE "%s" parameter is invalid: values must b

Error message

Value "%s" in RRULE "%s" parameter is invalid: values must be integers.

What it means

All RRULE filter setters (BYMONTH, BYHOUR, BYSETPOS, etc.) funnel through assertByRange(), which requires every value to be a real PHP integer. Even a numeric string like '5' is rejected, because the string '0' is truthy in PHP loose comparisons and the engine relies on integer semantics throughout evaluation.

Source

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

      }
    }

    sort($select);
    $select = array_unique($select);

    return array_select_keys($values, $select);
  }

  private function assertByRange(
    $source,
    array $values,
    $min,
    $max,
    $allow_zero = true) {

    foreach ($values as $value) {
      if (!is_int($value)) {
        throw new Exception(
          pht(
            'Value "%s" in RRULE "%s" parameter is invalid: values must be '.
            'integers.',
            $value,
            $source));
      }

      if ($value < $min || $value > $max) {
        throw new Exception(
          pht(
            'Value "%s" in RRULE "%s" parameter is invalid: it must be '.
            'between %s and %s.',
            $value,
            $source,
            $min,
            $max));
      }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Cast every value with intval() (or array_map('intval', $values)) before calling the setter
  2. Parse complete RRULE text through PhutilCalendarRecurrenceRule::newFromRRule() instead of assembling parts by hand
  3. Add a unit assertion in tests that setters receive int arrays

Example fix

// before
$rule->setByMonthDay(explode(',', $request->getStr('monthdays')));

// after
$rule->setByMonthDay(
  array_map('intval', explode(',', $request->getStr('monthdays'))));
Defensive patterns

Strategy: type-guard

Validate before calling

$values = array_map('intval', $values);
if (array_filter($values, 'is_string')) {
  throw new Exception('RRULE values must be integers.');
}

Type guard

function isIntList(array $values) {
  foreach ($values as $value) {
    if (!is_int($value)) {
      return false;
    }
  }
  return true;
}

if (!isIntList($monthdays)) {
  $monthdays = array_map('intval', $monthdays);
}

Try / catch

try {
  $rule->setByMonthDay($values);
} catch (Exception $ex) {
  throw new Exception('Non-integer recurrence values in user input.');
}

Prevention

When it happens

Trigger: Calling setByMonthDay(array('10','20')), setByHour(explode(',', $user_input)), or any setter fed with values that came from HTTP request data, explode() output, or JSON decoding without casting. Note that parsing an RRULE string via newFromRRule() already produces ints, so this only bites programmatic construction.

Common situations: Glue code that splits a comma-separated user string straight into a setter; data round-tripped through JSON with string values; refactors that replaced intval() with array keys from config arrays.

Related errors


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