{"record":{"id":"5ffae9e583709772","repo":"briannesbitt/Carbon","slug":"could-not-calculate-period-end-after-iterating-100","errorCode":null,"errorMessage":"Could not calculate period end after iterating 10000 times.","messagePattern":"Could not calculate period end after iterating 10000 times\\.","errorType":"exception","errorClass":"UnreachableException","httpStatus":null,"severity":"error","filePath":"src/Carbon/CarbonPeriod.php","lineNumber":2007,"sourceCode":"        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                ),\n            );\n        }\n\n        return null;\n    }\n\n    private function iterateUntilEnd(): ?CarbonInterface\n    {\n        $attempts = 0;\n        $date = null;\n\n        foreach ($this as $date) {\n            if (++$attempts > static::END_MAX_ATTEMPTS) {\n                throw new UnreachableException(\n                    'Could not calculate period end after iterating '.static::END_MAX_ATTEMPTS.' times.',\n                );\n            }\n        }\n\n        return $date;\n    }\n\n    /**\n     * Returns true if the current period overlaps the given one (if 1 parameter passed)\n     * or the period between 2 dates (if 2 parameters passed).\n     *\n     * @param CarbonPeriod|\\DateTimeInterface|Carbon|CarbonImmutable|string $rangeOrRangeStart\n     * @param \\DateTimeInterface|Carbon|CarbonImmutable|string|null         $rangeEnd\n     *\n     * @return bool\n     */\n    public function overlaps(mixed $rangeOrRangeStart, mixed $rangeEnd = null): bool","sourceCodeStart":1989,"sourceCodeEnd":2025,"githubUrl":"https://github.com/briannesbitt/Carbon/blob/b13f05955dcfd7da71d60af745fd148cbdb73505/src/Carbon/CarbonPeriod.php#L1989-L2025","documentation":"When calculateEnd() cannot derive the end arithmetically (e.g. custom filters exist, so the recurrences alone don't give the last date), it falls back to iterateUntilEnd(), stepping through the whole period date by date for up to END_MAX_ATTEMPTS (10000) iterations. If the true end lies farther than 10000 steps away, the search aborts with UnreachableException instead of running forever (src/Carbon/CarbonPeriod.php:2007).","triggerScenarios":"CarbonPeriod::create('2000-01-01', 'P1D')->setRecurrences(20000)->calculateEnd(); a period with custom filters spanning more than 10000 steps; a PT1S interval over several months; daily occurrences across 30+ years with a filter attached.","commonSituations":"Fine-grained intervals over long ranges; high recurrence counts in schedules; reports computing the 'last occurrence' of a filtered schedule.","solutions":["Compute the end arithmetically yourself when there are no filters: $start->copy()->add($interval->times($n - 1))","Calculate from an unfiltered copy with the same start/interval/recurrences (that path is O(1)), then keep the filters on the real period","Coarsen the interval or bound recurrences so the step count stays under CarbonPeriod::END_MAX_ATTEMPTS (10000)"],"exampleFix":"// before\n$end = CarbonPeriod::create('2000-01-01', 'P1D')\n    ->setRecurrences(20000)\n    ->calculateEnd(); // > 10000 iterations -> UnreachableException\n\n// after — arithmetic, no iteration\n$end = Carbon::parse('2000-01-01')->add(days: 20000 - 1);","handlingStrategy":"fallback","validationCode":"$steps = $period->getRecurrences() ?? INF;\nif (is_finite($steps) && $steps > CarbonPeriod::END_MAX_ATTEMPTS && \\count($period->getFilters()) > 1) {\n    // calculateEnd() would iterate each step; compute arithmetically instead\n    $end = $period->getStartDate()->copy()->add($period->getDateInterval()->times((int) $steps - 1));\n} else {\n    $end = $period->calculateEnd();\n}","typeGuard":null,"tryCatchPattern":"try {\n    $end = $period->calculateEnd();\n} catch (\\Carbon\\Exceptions\\UnreachableException $e) {\n    // too many steps: derive the end arithmetically from an unfiltered twin\n    $end = CarbonPeriod::create($period->getStartDate(), $period->getDateInterval())\n        ->setRecurrences($period->getRecurrences())\n        ->calculateEnd();\n}","preventionTips":["Avoid calculateEnd() on filtered, high-recurrence periods; compute the bound arithmetically","Keep intervals proportional to the range (don't step per-second over months)","Know the caps: CarbonPeriod::END_MAX_ATTEMPTS = 10000"],"tags":["carbon","carbon-period","iteration-limit","performance","calculate-end"],"backgroundTag":"iteration-limit-exceeded","analyzedSha":"b13f05955dcfd7da71d60af745fd148cbdb73505","analyzedAt":"2026-08-17T04:40:56.953Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}