briannesbitt/Carbon · error · UnreachableException
Could not calculate period end without either explicit end o
Error message
Could not calculate period end without either explicit end or recurrences. If you're looking for a forever-period, use ->setRecurrences(INF).
What it means
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).
Source
Thrown at src/Carbon/CarbonPeriod.php:1975
}
if ($this->dateInterval->isEmpty()) {
return $this->getStartDate($rounding);
}
$date = $this->getEndFromRecurrences() ?? $this->iterateUntilEnd();
if ($date && $rounding) {
$date = $date->avoidMutation()->round($this->getDateInterval(), $rounding);
}
return $date;
}
private function getEndFromRecurrences(): ?CarbonInterface
{
if ($this->carbonRecurrences === null) {
throw new UnreachableException(
"Could not calculate period end without either explicit end or recurrences.\n".
"If you're looking for a forever-period, use ->setRecurrences(INF).",
);
}
if ($this->carbonRecurrences === INF) {
$start = $this->getStartDate();
return $start < $start->avoidMutation()->add($this->getDateInterval())
? CarbonImmutable::endOfTime()
: CarbonImmutable::startOfTime();
}
if ($this->filters === [[static::RECURRENCES_FILTER, null]]) {
return $this->getStartDate()->avoidMutation()->add(
$this->getDateInterval()->times(
$this->carbonRecurrences - ($this->isStartExcluded() ? 0 : 1),
),View on GitHub (pinned to b13f05955d)
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
Example fix
// before
$end = CarbonPeriod::create('2021-01-01')->calculateEnd();
// after
$end = CarbonPeriod::create('2021-01-01')
->setRecurrences(30)
->calculateEnd(); Defensive patterns
Strategy: validation
Validate before calling
if ($period->getEndDate() === null && $period->getRecurrences() === null) {
throw new InvalidArgumentException('Period needs an end or recurrences before calculating its end');
}
$end = $period->calculateEnd(); Prevention
- 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
When it happens
Trigger: 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().
Common situations: 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.
Related errors
- Could not calculate period end after iterating 10000 times.
- Argument 1 passed to {$class}::{$method}() must be an instan
- Invalid ISO 8601 specification: {$iso}.
- $anchorDay parameter must not be set for $mode OverflowMode:
- You must specify $end or $recurrences but not both
AI-assisted analysis of briannesbitt/Carbon@b13f05955d (2026-08-17).
Data as JSON: /api/errors/f653881ad075c377.
Report an issue: GitHub.