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
TypedCacheItem::expiresAt() accepts only DateTimeInterface or null and uses get_debug_type() to report the offending type in a TypeError. It is the strict-typed variant of CacheItem used by the typed cache facade.
Solutions
- Wrap timestamps: new DateTimeImmutable('@' . $ts); parse strings: new DateTimeImmutable($str)
- Use expiresAfter() for relative TTLs
- Pass null to remove expiration
Example fix
// before $item->expiresAt($json['expires']); // string '2030-01-01T00:00:00Z' // after $item->expiresAt(new DateTimeImmutable($json['expires']));
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) { /* handle invalid expiration */ } Prevention
- Normalize all expiry inputs to DateTimeImmutable early
- Do not pass Unix timestamps to expiresAt; use new DateTimeImmutable('@'.$ts)
- Prefer expiresAfter for relative expiries
When it happens
Trigger: Passing an int timestamp, date string, DateInterval, or non-DateTimeInterface object to expiresAt() on a TypedCacheItem (or via the typed cache wrapper).
Common situations: Same confusion as CacheItem: Unix timestamp instead of DateTime; unparsed date string from JSON/API; switching from the untyped to typed item class and old code no longer type-checks (though native types usually catch this earlier).
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
- Expected $expiration to be an instance of DateTimeInterface…
- Expected $time to be either an integer, an instance of…
- Expected $time to be either an integer, an instance of…
- Cache key must be string
- Cache key length must be greater than zero.
AI-assisted analysis of doctrine/cache@e0a9919443 (2026-09-13).
Data as JSON: /api/errors/a821bab8350edcb7.
Report an issue: GitHub.
Appendix: source
Thrown at lib/Doctrine/Common/Cache/Psr6/TypedCacheItem.php:62
public function set(mixed $value): static
{
$this->value = $value;
return $this;
}
/**
* {@inheritDoc}
*/
public function expiresAt($expiration): static
{
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',
get_debug_type($expiration)
));
}
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)) {View on GitHub (pinned to e0a9919443)