doctrine/cache · error · InvalidArgument
Cache key " " contains reserved characters " ".
Error message
Cache key "%s" contains reserved characters "%s".
What it means
PSR-6 reserves the characters {}()/\@: in cache keys, and Doctrine's CacheAdapter enforces this via strpbrk against self::RESERVED_CHARACTERS. validKey() throws InvalidArgument when a key passed to getItem/hasItem/deleteItem/deleteItems/validKeys contains any of them.
Solutions
- Sanitize the key: replace reserved characters, e.g. preg_replace('/[{}()\/\\@:]/', '_', $key)
- Hash the offending value, e.g. md5() or sha1() of the raw identifier, to guarantee a safe key
- Prefix with a safe namespace and keep only safe parts of the raw value in the key
Example fix
// before
$item = $pool->getItem($email); // 'user@example.com'
// after
$item = $pool->getItem('email_' . md5($email)); Defensive patterns
Strategy: validation
Validate before calling
if (strpbrk($key, '{}()/\\@:') !== false) { $key = preg_replace('/[{}()\/\\@:]/', '_', $key); } Type guard
function hasNoReservedChars(string $key): bool { return strpbrk($key, '{}()/\\@:') === false; } Try / catch
try { $item = $pool->getItem($key); } catch (\Doctrine\Common\Cache\Psr6\InvalidArgument $e) { $item = $pool->getItem(md5($rawKey)); } Prevention
- Hash email addresses, paths, URLs and FQCNs used as keys
- Centralize key building in one sanitize helper
- Know the PSR-6 reserved set: {}()/\@:
When it happens
Trigger: Keys derived from file paths (/), emails (@), URLs (: /), class names with namespaces (\), or templates ({}) passed directly to the pool.
Common situations: Caching by email address or file path; using FQCN as a key; concatenating a URI segment containing ':'; keys built from user-supplied URLs.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- Cache key must be string
- Cache key length must be greater than zero.
- Expected $expiration to be an instance of DateTimeInterface…
- Expected $time to be either an integer, an instance of…
- Expected $expiration to be an instance of DateTimeInterface…
AI-assisted analysis of doctrine/cache@e0a9919443 (2026-09-13).
Data as JSON: /api/errors/fe8884b1b9456042.
Report an issue: GitHub.
Appendix: source
Thrown at lib/Doctrine/Common/Cache/Psr6/CacheAdapter.php:265
{
$this->commit();
}
/**
* @param mixed $key
*/
private static function validKey($key): bool
{
if (! is_string($key)) {
throw new InvalidArgument(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key)));
}
if ($key === '') {
throw new InvalidArgument('Cache key length must be greater than zero.');
}
if (strpbrk($key, self::RESERVED_CHARACTERS) !== false) {
throw new InvalidArgument(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS));
}
return true;
}
/**
* @param mixed[] $keys
*/
private static function validKeys(array $keys): bool
{
foreach ($keys as $key) {
self::validKey($key);
}
return true;
}
/**View on GitHub (pinned to e0a9919443)