doctrine/cache · error · TypeError

Expected $time to be either an integer, an instance of…

Error message

Expected $time to be either an integer, an instance of DateInterval or null, got %s

What it means

TypedCacheItem::expiresAfter() accepts null, int seconds, or DateInterval; anything else raises a TypeError with the debug type embedded via get_debug_type(). This mirrors CacheItem::expiresAfter but in the typed item class.

Solutions

  1. Cast to int: expiresAfter((int) $ttl)
  2. Convert interval strings with new DateInterval($spec)
  3. Use expiresAt() with DateTimeImmutable for absolute expiry

Example fix

// before
$item->expiresAfter(getenv('CACHE_TTL')); // string
// after
$item->expiresAfter((int) getenv('CACHE_TTL'));
Defensive patterns

Strategy: type-guard

Validate before calling

if ($time !== null && !is_int($time) && !$time instanceof \DateInterval) { throw new InvalidArgumentException('time must be int, DateInterval or null'); }

Type guard

function acceptsTtl(mixed $v): bool { return $v === null || is_int($v) || $v instanceof \DateInterval; }

Try / catch

try { $item->expiresAfter($ttl); } catch (\TypeError $e) { /* coerce or report */ }

Prevention

When it happens

Trigger: Calling expiresAfter() with a string TTL from config/env, a float, or a DateTime object instead of the accepted types.

Common situations: TTL values sourced from .env or JSON as strings; refactors moving from untyped to typed cache items; passing DateInterval where int was expected is fine, but strings are not auto-parsed.

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/573f51e7495a4325. Report an issue: GitHub.

Appendix: source

Thrown at lib/Doctrine/Common/Cache/Psr6/TypedCacheItem.php:83

            ));
        }

        return $this;
    }

    /**
     * {@inheritDoc}
     */
    public function expiresAfter($time): static
    {
        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)) {
            $this->expiry = $time + microtime(true);
        } else {
            throw new TypeError(sprintf(
                'Expected $time to be either an integer, an instance of DateInterval or null, got %s',
                get_debug_type($time)
            ));
        }

        return $this;
    }

    /**
     * @internal
     */
    public function getExpiry(): ?float
    {
        return $this->expiry;
    }
}

View on GitHub (pinned to e0a9919443)