{"record":{"id":"9a06514488b43215","repo":"phacility/phabricator","slug":"value-s-in-rrule-s-parameter-is-invalid-val","errorCode":null,"errorMessage":"Value \"%s\" in RRULE \"%s\" parameter is invalid: values must be integers.","messagePattern":"Value \"(.+?)\" in RRULE \"(.+?)\" parameter is invalid: values must be integers\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/calendar/parser/data/PhutilCalendarRecurrenceRule.php","lineNumber":1587,"sourceCode":"      }\n    }\n\n    sort($select);\n    $select = array_unique($select);\n\n    return array_select_keys($values, $select);\n  }\n\n  private function assertByRange(\n    $source,\n    array $values,\n    $min,\n    $max,\n    $allow_zero = true) {\n\n    foreach ($values as $value) {\n      if (!is_int($value)) {\n        throw new Exception(\n          pht(\n            'Value \"%s\" in RRULE \"%s\" parameter is invalid: values must be '.\n            'integers.',\n            $value,\n            $source));\n      }\n\n      if ($value < $min || $value > $max) {\n        throw new Exception(\n          pht(\n            'Value \"%s\" in RRULE \"%s\" parameter is invalid: it must be '.\n            'between %s and %s.',\n            $value,\n            $source,\n            $min,\n            $max));\n      }\n","sourceCodeStart":1569,"sourceCodeEnd":1605,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/calendar/parser/data/PhutilCalendarRecurrenceRule.php#L1569-L1605","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Cast every value with intval() (or array_map('intval', $values)) before calling the setter","Parse complete RRULE text through PhutilCalendarRecurrenceRule::newFromRRule() instead of assembling parts by hand","Add a unit assertion in tests that setters receive int arrays"],"exampleFix":"// before\n$rule->setByMonthDay(explode(',', $request->getStr('monthdays')));\n\n// after\n$rule->setByMonthDay(\n  array_map('intval', explode(',', $request->getStr('monthdays'))));","handlingStrategy":"type-guard","validationCode":"$values = array_map('intval', $values);\nif (array_filter($values, 'is_string')) {\n  throw new Exception('RRULE values must be integers.');\n}","typeGuard":"function isIntList(array $values) {\n  foreach ($values as $value) {\n    if (!is_int($value)) {\n      return false;\n    }\n  }\n  return true;\n}\n\nif (!isIntList($monthdays)) {\n  $monthdays = array_map('intval', $monthdays);\n}","tryCatchPattern":"try {\n  $rule->setByMonthDay($values);\n} catch (Exception $ex) {\n  throw new Exception('Non-integer recurrence values in user input.');\n}","preventionTips":["Never feed explode() or JSON-decoded values into setters without array_map('intval', ...)","Prefer parsing complete RRULE text with newFromRRule() over hand-assembling rules","Remember PHP's is_int('5') is false — cast explicitly, do not rely on coercion"],"tags":["rrule","php","type-validation","calendar"],"backgroundTag":"parameter-type-validation","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}