{"record":{"id":"b1e3ca80a77db30a","repo":"phacility/phabricator","slug":"unexpected-value-s-in-s-rule-property-expec","errorCode":null,"errorMessage":"Unexpected value \"%s\" in \"%s\" RULE property: expected an integer.","messagePattern":"Unexpected value \"(.+?)\" in \"(.+?)\" RULE property: expected an integer\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/calendar/parser/data/PhutilCalendarRecurrenceRule.php","lineNumber":280,"sourceCode":"        'BYHOUR',\n        'BYMONTH',\n        'BYMONTHDAY',\n        'BYYEARDAY',\n        'BYWEEKNO',\n        'BYSETPOS',\n      ));\n\n    $int_values = array_fuse(\n      array(\n        'COUNT',\n        'INTERVAL',\n      ));\n\n    foreach ($dict as $key => $value) {\n      if (isset($int_values[$key])) {\n        // None of these values may be negative.\n        if (!preg_match('/^\\d+\\z/', $value)) {\n          throw new Exception(\n            pht(\n              'Unexpected value \"%s\" in \"%s\" RULE property: expected an '.\n              'integer.',\n              $value,\n              $key));\n        }\n        $dict[$key] = (int)$value;\n      }\n\n      if (isset($int_lists[$key])) {\n        foreach ($value as $k => $v) {\n          if (!preg_match('/^-?\\d+\\z/', $v)) {\n            throw new Exception(\n              pht(\n                'Unexpected value \"%s\" in \"%s\" RRULE property: expected '.\n                'only integers.',\n                $v,\n                $key));","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/calendar/parser/data/PhutilCalendarRecurrenceRule.php#L262-L298","documentation":"While normalizing an RRULE dictionary, the scalar integer properties COUNT and INTERVAL must match /^\\d+$/ (a non-negative integer string). Negative numbers, decimals, or non-numeric values throw before the cast to int. Note the message text says 'RULE property' (the RRULE spelling used elsewhere is inconsistent).","triggerScenarios":"Dict with 'COUNT' => '-5', 'INTERVAL' => '1.5', 'COUNT' => 'weekly', or values that arrived as free text from an ICS producer. Plain PHP ints are fine because preg_match stringifies them.","commonSituations":"Hand-built dicts from user input; ICS files with malformed RRULE parts; JSON round-trips that mangle numbers into strings like '1.0'.","solutions":["Coerce values before building the dict: $dict['COUNT'] = (string)(int)$count with $count >= 0.","Reject or sanitize external ICS values that do not match ^\\d+$.","Remember COUNT=0 passes this check but later throws in setCount(); keep COUNT >= 1."],"exampleFix":"// before\n$dict['INTERVAL'] = '2x';\n// after\n$dict['INTERVAL'] = (string)(int)$interval;","handlingStrategy":"type-guard","validationCode":"// Coerce scalar integer fields before building the dict:\nforeach (array('COUNT', 'INTERVAL') as $k) {\n  if (isset($dict[$k]) && preg_match('/^\\d+$/', (string)$dict[$k])) {\n    $dict[$k] = (string)(int)$dict[$k];\n  } else {\n    unset($dict[$k]); // drop invalid values instead of throwing later\n  }\n}","typeGuard":"function isNonNegativeIntegerString($value) {\n  return is_string($value) && preg_match('/^\\d+$/', $value)\n    || is_int($value) && $value >= 0;\n}","tryCatchPattern":"try {\n  $rule = PhutilCalendarRecurrenceRule::newFromDictionary($dict);\n} catch (Exception $ex) {\n  phlog($ex->getMessage()); // identifies the offending property and value\n  continue;\n}","preventionTips":["Cast COUNT/INTERVAL to ints at the boundary where external data enters.","Reject '+'-prefixed, decimal, or negative values early.","Remember COUNT must be >= 1 to survive setCount() as well."],"tags":["phutil","calendar","rrule","validation","type-error"],"backgroundTag":"expected-integer","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}