symfony/symfony · error · Symfony\Component\Cache\Exception\InvalidArgumentException
Cache key "%s" contains reserved characters "%s".
Error message
Cache key "%s" contains reserved characters "%s".
What it means
PSR-6 cache keys must not contain reserved characters defined in ItemInterface::RESERVED_CHARACTERS = '{}()/\\@:'. These characters are reserved because they are used as delimiters in Symfony's internal key normalization and namespace schemes, and they are also problematic for many storage backends (Redis, filesystem, Memcached). CacheItem::validateKey() throws an InvalidArgumentException when strpbrk() finds any of them in the key.
Source
Thrown at src/Symfony/Component/Cache/CacheItem.php:140
}
/**
* Validates a cache key according to PSR-6.
*
* @param mixed $key The key to validate
*
* @throws InvalidArgumentException When $key is not valid
*/
public static function validateKey($key): string
{
if (!\is_string($key)) {
throw new InvalidArgumentException(\sprintf('Cache key must be string, "%s" given.', get_debug_type($key)));
}
if ('' === $key) {
throw new InvalidArgumentException('Cache key length must be greater than zero.');
}
if (false !== strpbrk($key, self::RESERVED_CHARACTERS)) {
throw new InvalidArgumentException(\sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS));
}
return $key;
}
/**
* Internal logging helper.
*
* @internal
*/
public static function log(?LoggerInterface $logger, string $message, array $context = []): void
{
if ($logger) {
$logger->warning($message, $context);
} else {
$replace = [];
foreach ($context as $k => $v) {
if (\is_scalar($v)) {View on GitHub (pinned to 698e28026c)
Solutions
- Replace reserved characters before use: str_replace(['{','}','(',')','/','\\','@',':'], '_', $key).
- Hash complex keys: $safeKey = hash('xxh128', $rawKey) or md5($rawKey).
- Design keys using only alphanumeric characters, underscores, dots, and dashes.
Example fix
// before
$pool->getItem('/api/users/123'); // slashes are reserved
$pool->getItem('App\\Entity\\User'); // backslash is reserved
// after
$pool->getItem('api_users_123');
$pool->getItem(hash('xxh128', $uri)); Defensive patterns
Strategy: validation
Validate before calling
use Symfony\Contracts\Cache\ItemInterface; $key = str_replace(str_split(ItemInterface::RESERVED_CHARACTERS), '_', $key); $item = $pool->getItem($key);
Type guard
function keyHasReservedChars(string $key): bool {
return false !== strpbrk($key, \Symfony\Contracts\Cache\ItemInterface::RESERVED_CHARACTERS);
} Try / catch
try {
$item = $pool->getItem($key);
} catch (\Symfony\Component\Cache\Exception\InvalidArgumentException $e) {
$key = str_replace(str_split(\Symfony\Contracts\Cache\ItemInterface::RESERVED_CHARACTERS), '_', $key);
$item = $pool->getItem($key);
} Prevention
- Design cache keys with only [a-zA-Z0-9._-] characters.
- Hash complex/unsafe keys with md5() or xxh128().
- Sanitize URI paths and namespace strings before caching.
When it happens
Trigger: Calling $pool->getItem('user:profile') (colon), $pool->getItem('app/data/key') (slash), $pool->getItem('cache@v2') (at), or any key containing { } ( ) \ characters.
Common situations: Using natural keys like URIs ('/api/users/123'), class names with namespace separators ('App\Entity\User'), or email-style identifiers directly as cache keys. Common when caching by URL path or by FQCN.
Related errors
- Expiration date must be an integer, a DateInterval or null,
- Cache tag must be string or object that implements __toStrin
- Cache tag length must be greater than zero.
- Cache tag "%s" contains reserved characters "%s".
- Cache key must be string, "%s" given.
AI-assisted analysis of symfony/symfony@698e28026c (2026-08-06).
Data as JSON: /api/errors/d0b9a55583bb677d.
Report an issue: GitHub.