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

  1. Replace reserved characters before use: str_replace(['{','}','(',')','/','\\','@',':'], '_', $key).
  2. Hash complex keys: $safeKey = hash('xxh128', $rawKey) or md5($rawKey).
  3. 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

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


AI-assisted analysis of symfony/symfony@698e28026c (2026-08-06). Data as JSON: /api/errors/d0b9a55583bb677d. Report an issue: GitHub.