{"record":{"id":"f653881ad075c377","repo":"briannesbitt/Carbon","slug":"could-not-calculate-period-end-without-either-expl","errorCode":null,"errorMessage":"Could not calculate period end without either explicit end or recurrences.\nIf you're looking for a forever-period, use ->setRecurrences(INF).","messagePattern":"Could not calculate period end without either explicit end or recurrences\\.\nIf you're looking for a forever-period, use ->setRecurrences\\(INF\\)\\.","errorType":"exception","errorClass":"UnreachableException","httpStatus":null,"severity":"error","filePath":"src/Carbon/CarbonPeriod.php","lineNumber":1975,"sourceCode":"        }\n\n        if ($this->dateInterval->isEmpty()) {\n            return $this->getStartDate($rounding);\n        }\n\n        $date = $this->getEndFromRecurrences() ?? $this->iterateUntilEnd();\n\n        if ($date && $rounding) {\n            $date = $date->avoidMutation()->round($this->getDateInterval(), $rounding);\n        }\n\n        return $date;\n    }\n\n    private function getEndFromRecurrences(): ?CarbonInterface\n    {\n        if ($this->carbonRecurrences === null) {\n            throw new UnreachableException(\n                \"Could not calculate period end without either explicit end or recurrences.\\n\".\n                \"If you're looking for a forever-period, use ->setRecurrences(INF).\",\n            );\n        }\n\n        if ($this->carbonRecurrences === INF) {\n            $start = $this->getStartDate();\n\n            return $start < $start->avoidMutation()->add($this->getDateInterval())\n                ? CarbonImmutable::endOfTime()\n                : CarbonImmutable::startOfTime();\n        }\n\n        if ($this->filters === [[static::RECURRENCES_FILTER, null]]) {\n            return $this->getStartDate()->avoidMutation()->add(\n                $this->getDateInterval()->times(\n                    $this->carbonRecurrences - ($this->isStartExcluded() ? 0 : 1),\n                ),","sourceCodeStart":1957,"sourceCodeEnd":1993,"githubUrl":"https://github.com/briannesbitt/Carbon/blob/b13f05955dcfd7da71d60af745fd148cbdb73505/src/Carbon/CarbonPeriod.php#L1957-L1993","documentation":"calculateEnd() returns the explicit end date or computes one. Computation needs either an end date or a recurrences bound; with neither there is no definable last date, so UnreachableException is thrown with a hint to use ->setRecurrences(INF) for deliberate forever-periods (src/Carbon/CarbonPeriod.php:1975).","triggerScenarios":"CarbonPeriod::create('2021-01-01')->calculateEnd(); any unbounded period (start only) fed to an API that needs the last date, e.g. ->getIncludedEndDate() flows or range comparison helpers that call calculateEnd().","commonSituations":"Generic reporting code calling calculateEnd() on periods built from optional user filters where the 'until' filter may be absent; forgetting create($start) alone is unbounded; migrating code that assumed an implicit end.","solutions":["Bound the period first: ->setRecurrences($n) or ->setEndDate($date)","For an intentional infinite period: ->setRecurrences(INF) (the end then resolves to start/end of time)","Branch explicitly: if ($period->getEndDate() === null && $period->getRecurrences() === null) handle the unbounded case before calling"],"exampleFix":"// before\n$end = CarbonPeriod::create('2021-01-01')->calculateEnd();\n\n// after\n$end = CarbonPeriod::create('2021-01-01')\n    ->setRecurrences(30)\n    ->calculateEnd();","handlingStrategy":"validation","validationCode":"if ($period->getEndDate() === null && $period->getRecurrences() === null) {\n    throw new InvalidArgumentException('Period needs an end or recurrences before calculating its end');\n}\n$end = $period->calculateEnd();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat 'no end and no recurrences' as an invalid state in your own model; enforce bounds when periods are constructed","Use setRecurrences(INF) when forever is intentional, so calculateEnd() returns end/start of time instead of throwing"],"tags":["carbon","carbon-period","unbounded-period","calculate-end"],"backgroundTag":"unbounded-period-end","analyzedSha":"b13f05955dcfd7da71d60af745fd148cbdb73505","analyzedAt":"2026-08-17T04:40:56.953Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}