briannesbitt/Carbon · error · InvalidArgumentException
You must specify $end or $recurrences but not both
Error message
You must specify $end or $recurrences but not both
What it means
The cycle constructors CarbonPeriod::monthly()/quarterly()/yearly() bound the period either by an explicit $end date or by a count of $recurrences. Supplying both is ambiguous (which bound wins?), so getStartAndEndForCyclePeriod() rejects the combination immediately (src/Carbon/CarbonPeriod.php:582).
Source
Thrown at src/Carbon/CarbonPeriod.php:582
return $count ? $result : $target;
}
private static function getStartAndEndForCyclePeriod(
DateTimeInterface|string|int|null $start = null,
DateTimeInterface|string|int|null $end = null,
?int $recurrences = null,
?int $anchorDay = null,
OverflowMode $mode = OverflowMode::AnchorDay,
): array {
if ($anchorDay !== null && $mode !== OverflowMode::AnchorDay) {
throw new InvalidArgumentException(
'$anchorDay parameter must not be set for $mode OverflowMode::'.$mode->name,
);
}
if ($end !== null && $recurrences !== null) {
throw new InvalidArgumentException(
'You must specify $end or $recurrences but not both',
);
}
if (\is_int($start)) {
$start = CarbonImmutable::createFromTimestamp($start);
} elseif (\is_string($start)) {
$start = CarbonImmutable::parse($start);
}
$start ??= CarbonImmutable::now();
if (\is_int($end)) {
$end = CarbonImmutable::createFromTimestamp($end);
}
return [$start, $end];
}View on GitHub (pinned to b13f05955d)
Solutions
- Pass only one bound: either the end date or the recurrence count
- Make the config unambiguous: when both are present, pick one (e.g. prefer the end date) before calling
- Build incrementally with individually safe setters: CarbonPeriod::monthly($start)->setRecurrences(12) or ->setEndDate($end)
Example fix
// before
$period = CarbonPeriod::monthly('2021-01-31', '2021-12-31', 12);
// after — choose one bound
$period = CarbonPeriod::monthly('2021-01-31', '2021-12-31');
// or
$period = CarbonPeriod::monthly('2021-01-31', null, 12); Defensive patterns
Strategy: validation
Validate before calling
if ($end !== null && $recurrences !== null) {
throw new InvalidArgumentException('Pass either $end or $recurrences, not both');
}
$period = CarbonPeriod::monthly($start, $end, $recurrences); Prevention
- When reading schedule config, apply precedence explicitly (e.g. end date wins, recurrences otherwise) before calling cycle constructors
- Prefer chaining ->setEndDate()/->setRecurrences() so bounds are added one at a time
When it happens
Trigger: CarbonPeriod::monthly('2021-01-31', '2021-12-31', 12); CarbonPeriod::yearly($start, $end, 5) — any call where both $end and $recurrences are non-null.
Common situations: Config-driven schedules where both 'end_date' and 'occurrences' keys are set and both get forwarded; copy-pasting between create() and monthly() whose argument positions differ.
Related errors
- Invalid ISO 8601 specification: {$iso}.
- $anchorDay parameter must not be set for $mode OverflowMode:
- Argument 1 passed to {$class}::{$method}() must be an instan
- Invalid constructor parameters.
- $name
AI-assisted analysis of briannesbitt/Carbon@b13f05955d (2026-08-17).
Data as JSON: /api/errors/fe5a216d01c82986.
Report an issue: GitHub.