{"record":{"id":"5cc7c5233ef3e841","repo":"phacility/phabricator","slug":"sequence-s-is-not-valid-for-event","errorCode":null,"errorMessage":"Sequence \"%s\" is not valid for event!","messagePattern":"Sequence \"(.+?)\" is not valid for event!","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/calendar/storage/PhabricatorCalendarEvent.php","lineNumber":219,"sourceCode":"    $this\n      ->setHostPHID($parent->getHostPHID())\n      ->setIsAllDay($parent->getIsAllDay())\n      ->setIcon($parent->getIcon())\n      ->setSpacePHID($parent->getSpacePHID())\n      ->setViewPolicy($parent->getViewPolicy())\n      ->setEditPolicy($parent->getEditPolicy())\n      ->setName($parent->getName())\n      ->setDescription($parent->getDescription())\n      ->setIsCancelled($parent->getIsCancelled());\n\n    if ($start) {\n      $start_datetime = $start;\n    } else {\n      $sequence = $this->getSequenceIndex();\n      $start_datetime = $parent->newSequenceIndexDateTime($sequence);\n\n      if (!$start_datetime) {\n        throw new Exception(\n          pht(\n            'Sequence \"%s\" is not valid for event!',\n            $sequence));\n      }\n    }\n\n    $duration = $parent->newDuration();\n    $end_datetime = $start_datetime->newRelativeDateTime($duration);\n\n    $this\n      ->setStartDateTime($start_datetime)\n      ->setEndDateTime($end_datetime);\n\n    if ($parent->isImportedEvent()) {\n      $full_uid = $parent->getImportUID().'/'.$start_datetime->getEpoch();\n\n      // NOTE: We don't attach the import source because this gets called\n      // from CalendarEventQuery while building ghosts, before we've loaded","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/calendar/storage/PhabricatorCalendarEvent.php#L201-L237","documentation":"When a child instance of a recurring event is materialized without an explicit start datetime, the parent computes the start from the instance's stored sequence index via newSequenceIndexDateTime(). That method returns null when the index no longer maps to an occurrence — the recurrence set is empty, or a COUNT limit cuts off before this sequence — and materialization throws.","triggerScenarios":"A stored instance row (e.g. one with a cancelled/edited sequence) whose sequence index exceeds the parent's current COUNT (the rule was edited to 'repeat 5 times' while an instance for sequence 8 exists), or whose parent lost its recurrence data so newRecurrenceSet() returns empty.","commonSituations":"Editing a recurring event's occurrence count or DTSTART after instances were created; data restored from backup where parent and child rows are out of sync; corrupted imports that wrote child rows with bogus sequence indexes.","solutions":["Repair the data: delete the stale child instance rows (they will be regenerated as ghosts on demand) or fix the sequence index to match the parent's current recurrence","Verify the parent's recurrence is intact (frequency, count, until) before querying with ghost generation","If the parent was intentionally shortened, run the repair/reindex so orphaned sequences are pruned"],"exampleFix":"// before (instance row for sequence 8 while parent rule is COUNT=5)\n$event->newStub($viewer, $sequence)->save();\n\n// after: validate against the parent before touching the instance\n$parent = $event->getInstanceOfEvent();\nif (!$parent || !$parent->isValidSequenceIndex($viewer, $sequence)) {\n  continue; // stale instance; skip or prune it\n}","handlingStrategy":"try-catch","validationCode":"$parent = id(new PhabricatorCalendarEventQuery())\n  ->setViewer($viewer)\n  ->withPHIDs(array($event->getInstanceOfEventPHID()))\n  ->executeOne();\nif ($parent && !$parent->isValidSequenceIndex($viewer, $sequence)) {\n  // Skip or prune the stale instance instead of materializing it.\n  continue;\n}","typeGuard":null,"tryCatchPattern":"try {\n  $datetime = $parent->newSequenceIndexDateTime($sequence);\n} catch (Exception $ex) {\n  // Sequence no longer resolves under the parent's current rule:\n  // drop the stale child row and let ghosts regenerate as needed.\n  $event->delete();\n  continue;\n}","preventionTips":["After editing a recurring event's COUNT/UNTIL/DTSTART, prune child instances whose sequence indexes fall outside the new rule","Use isValidSequenceIndex($viewer, $sequence) before touching stored instances","Alert on parent/child drift during data restores — it is the usual root cause"],"tags":["phabricator","calendar","recurring-events","data-integrity"],"backgroundTag":"stale-denormalized-data","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}