briannesbitt/Carbon · error · InvalidPeriodDateException

Invalid end date.

Error message

Invalid end date.

What it means

setEndDate() converts its input through the period's date class ::make() exactly like setStartDate(); unparseable values make ::make() return null and InvalidPeriodDateException('Invalid end date.') is thrown (src/Carbon/CarbonPeriod.php:1397). Note that null is VALID here — it removes the end filter — and infinite markers (INF) are accepted.

Source

Thrown at src/Carbon/CarbonPeriod.php:1397

        $self->syncNativePeriod();

        return $self;
    }

    /**
     * Change the period end date.
     *
     * @param DateTime|DateTimeInterface|string|null $date
     * @param bool|null                              $inclusive
     *
     * @throws \InvalidArgumentException
     *
     * @return static
     */
    public function setEndDate(mixed $date, ?bool $inclusive = null): static
    {
        if ($date !== null && !$this->isInfiniteDate($date) && !$date = ([$this->dateClass, 'make'])($date, $this->timezone)) {
            throw new InvalidPeriodDateException('Invalid end date.');
        }

        // ::make() is responsible for converting strings to DateTimeInterface objects
        \assert(!\is_string($date));

        $self = $this->copyIfImmutable();

        if (!$date) {
            $self = $self->removeFilter(static::END_DATE_FILTER);
            $self->syncNativePeriod();

            return $self;
        }

        \assert($date instanceof DateTimeInterface);

        $self->endDate = $date;

View on GitHub (pinned to b13f05955d)

Solutions

  1. Validate/parse first: Carbon::hasFormat() or try/catch around Carbon::parse()
  2. Pass a DateTimeInterface instance
  3. Pass null deliberately when you want no end bound — do not use a junk string as a sentinel

Example fix

// before
$period->setEndDate($request->input('to', '')); // '' -> Invalid end date

// after
$to = trim((string) $request->input('to', ''));
$period->setEndDate($to === '' ? null : Carbon::parse($to));
Defensive patterns

Strategy: validation

Validate before calling

if ($date !== null && \is_string($date) && Carbon::make($date) === null) {
    throw new InvalidArgumentException('Unparseable end date: '.$date);
}
$period->setEndDate($date); // null is valid and removes the end bound

Try / catch

try {
    $period->setEndDate($input);
} catch (\Carbon\Exceptions\InvalidPeriodDateException $e) {
    throw new ValidationException('end: must be a valid date', 0, $e);
}

Prevention

When it happens

Trigger: ->setEndDate('foo'); ->setEndDate('2021-02-31'); ->setEndDate($emptyString) — any value Carbon cannot parse into a date (null excepted).

Common situations: 'To' fields in reports left half-filled; date strings with locale month names; trailing whitespace/newlines from CSV or spreadsheets breaking parse.

Related errors


AI-assisted analysis of briannesbitt/Carbon@b13f05955d (2026-08-17). Data as JSON: /api/errors/a30a7b9473bd5af5. Report an issue: GitHub.