briannesbitt/Carbon · error · InvalidPeriodParameterException
Invalid ISO 8601 specification: {$iso}.
Error message
Invalid ISO 8601 specification: {$iso}. What it means
Strings passed to CarbonPeriod::create()/createFromISO() are treated as ISO 8601 repetition specs split on '/': an optional leading R<n>/RINF part, then at most interval, start and end segments, each of which must parse as a CarbonInterval or a date (the end may borrow missing parts from the start via addMissingParts()). When a segment cannot fill the next expected slot — too many segments, or one that is neither a valid interval nor a parseable date — the whole spec is rejected (src/Carbon/CarbonPeriod.php:547).
Source
Thrown at src/Carbon/CarbonPeriod.php:547
{
$result = [];
$interval = null;
$start = null;
$end = null;
$dateClass = static::DEFAULT_DATE_CLASS;
foreach (explode('/', $iso) as $key => $part) {
if ($key === 0 && preg_match('/^R(\d*|INF)$/', $part, $match)) {
$parsed = \strlen($match[1]) ? (($match[1] !== 'INF') ? (int) $match[1] : INF) : null;
} elseif ($interval === null && $parsed = self::makeInterval($part)) {
$interval = $part;
} elseif ($start === null && $parsed = $dateClass::make($part)) {
$start = $part;
} elseif ($end === null && $parsed = $dateClass::make(static::addMissingParts($start ?? '', $part))) {
$end = $part;
} else {
throw new InvalidPeriodParameterException("Invalid ISO 8601 specification: $iso.");
}
$result[] = $parsed;
}
return $result;
}
/**
* Add missing parts of the target date from the source date.
*/
protected static function addMissingParts(string $source, string $target): string
{
$pattern = '/'.preg_replace('/\d+/', '[0-9]+', preg_quote($target, '/')).'$/';
$result = preg_replace($pattern, $target, $source, 1, $count);
return $count ? $result : $target;View on GitHub (pinned to b13f05955d)
Solutions
- Pass the pieces as separate arguments instead of one ISO string: CarbonPeriod::create($start, 'P1D')->setRecurrences(4)
- Fix the spec layout: R<n>/<start>/<interval>/<end>, at most 4 segments, dates before a trailing interval are fine
- Validate at the boundary: regex-check the shape, then try CarbonInterval::make()/Carbon::hasFormat() per segment and reject bad input early
Example fix
// before
$period = CarbonPeriod::create('R4/2021-01-01/P1D/nope');
// after
$period = CarbonPeriod::create('2021-01-01', 'P1D')->setRecurrences(4);
// or a corrected spec
$period = CarbonPeriod::create('R4/2021-01-01/P1D'); Defensive patterns
Strategy: validation
Validate before calling
function isValidIsoSpec(string $iso): bool
{
$parts = explode('/', $iso);
if (\count($parts) > 4) {
return false;
}
$i = 0;
if (preg_match('/^R(\d*|INF)$/', $parts[0])) {
$i = 1;
}
for (; $i < \count($parts); $i++) {
$part = $parts[$i];
if (CarbonInterval::make($part) === null && Carbon::hasFormat($part, 'Y-m-d\TH:i:s') === false && Carbon::make($part) === null) {
return false;
}
}
return true;
}
if (!isValidIsoSpec($iso)) {
throw new InvalidArgumentException("Bad ISO 8601 period spec: $iso");
} Try / catch
try {
$period = CarbonPeriod::createFromISO8601String($iso);
} catch (\Carbon\Exceptions\InvalidPeriodParameterException $e) {
// fall back to explicit construction
$period = CarbonPeriod::create($defaultStart, 'P1D', $defaultEnd);
} Prevention
- Treat ISO period specs as a strict external format: validate shape and segment count before use
- Prefer multi-argument create($start, $interval, $end) whenever the pieces are separate variables
- Add unit tests covering malformed specs from user input
When it happens
Trigger: CarbonPeriod::create('R4/2021-01-01/P1D/extra') (a 5th segment has no slot); CarbonPeriod::create('hello/world') ('world' is neither interval nor date); CarbonPeriod::create('P1D/not-a-date'); US m/d/Y dates like '01/31/2021' injected as a segment producing empty or unparseable parts.
Common situations: User-supplied recurrence strings (API query params, scheduled-task config); concatenating variables where one is empty and yields '//' segments; mis-remembering the spec order and putting the interval last after both dates.
Related errors
- You must specify $end or $recurrences but not both
- Invalid interval.
- Argument 1 passed to {$class}::{$method}() must be an instan
- $anchorDay parameter must not be set for $mode OverflowMode:
- Invalid constructor parameters.
AI-assisted analysis of briannesbitt/Carbon@b13f05955d (2026-08-17).
Data as JSON: /api/errors/d3053e9b4ee6bd13.
Report an issue: GitHub.