doctrine/cache · error · TypeError

Expected $expiration to be an instance of DateTimeInterface…

Error message

Expected $expiration to be an instance of DateTimeInterface or null, got %s

What it means

CacheItem::expiresAt() accepts only a DateTimeInterface implementation (DateTime/DateTimeImmutable) or null; anything else triggers a TypeError. This enforces the PSR-6 contract that expiration must be an absolute point in time.

Solutions

  1. Convert to a DateTime object first, e.g. new DateTimeImmutable('@' . $ts) for timestamps or new DateTimeImmutable($dateString) for strings
  2. Use expiresAfter() instead if you have a relative TTL (int seconds or DateInterval)
  3. Pass null explicitly to clear the expiration rather than 0 or false

Example fix

// before
$item->expiresAt(time() + 3600); // int
// after
$item->expiresAt(new DateTimeImmutable('+1 hour'));
Defensive patterns

Strategy: type-guard

Validate before calling

if ($expiration !== null && !$expiration instanceof \DateTimeInterface) { throw new InvalidArgumentException('expiration must be DateTimeInterface or null'); }

Type guard

function acceptsExpiration(mixed $v): bool { return $v === null || $v instanceof \DateTimeInterface; }

Try / catch

try { $item->expiresAt($expiration); } catch (\TypeError $e) { /* convert and retry */ }

Prevention

When it happens

Trigger: Calling $item->expiresAt($value) where $value is an int timestamp, a date string, a DateInterval, a custom date-like object not implementing DateTimeInterface, or a string from an API.

Common situations: Passing a Unix timestamp integer (common confusion with expiresAfter); passing a date string from JSON/config without parsing; using Carbon versions/objects that do not implement DateTimeInterface (rare, Carbon does implement it).

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of doctrine/cache@e0a9919443 (2026-09-13). Data as JSON: /api/errors/eab1ab5a1cec3019. Report an issue: GitHub.

Appendix: source

Thrown at lib/Doctrine/Common/Cache/Psr6/CacheItem.php:81

     */
    public function set($value): self
    {
        $this->value = $value;

        return $this;
    }

    /**
     * {@inheritDoc}
     */
    public function expiresAt($expiration): self
    {
        if ($expiration === null) {
            $this->expiry = null;
        } elseif ($expiration instanceof DateTimeInterface) {
            $this->expiry = (float) $expiration->format('U.u');
        } else {
            throw new TypeError(sprintf(
                'Expected $expiration to be an instance of DateTimeInterface or null, got %s',
                is_object($expiration) ? get_class($expiration) : gettype($expiration)
            ));
        }

        return $this;
    }

    /**
     * {@inheritDoc}
     */
    public function expiresAfter($time): self
    {
        if ($time === null) {
            $this->expiry = null;
        } elseif ($time instanceof DateInterval) {
            $this->expiry = microtime(true) + DateTime::createFromFormat('U', 0)->add($time)->format('U.u');
        } elseif (is_int($time)) {

View on GitHub (pinned to e0a9919443)