doctrine/cache · error · InvalidArgument

Cache key must be string

Error message

Cache key must be string, "%s" given.

What it means

Doctrine's PSR-6 CacheAdapter requires cache keys to be non-empty strings without reserved characters. validKey() throws this InvalidArgument when getItem, hasItem, deleteItem, deleteItems, or validKeys receives a key that is not a string. The message reports the PHP type (or class name) of the value actually passed.

Solutions

  1. Cast or build the key as a string before calling the pool, e.g. (string) $id or 'user_' . $id
  2. If the key is an object, derive a string from it (e.g. ->getId() or serialize/md5 of a stable representation)
  3. Guard with is_string($key) before calling the adapter and handle invalid input at the boundary
  4. Check callers for null values from config/databases that flow into the key position

Example fix

// before
$item = $pool->getItem($row['id']); // int
// after
$item = $pool->getItem((string) $row['id']);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!is_string($key) || $key === '') { throw new InvalidArgumentException('Invalid cache key'); }

Type guard

function isStringKey(mixed $key): bool { return is_string($key) && $key !== ''; }

Try / catch

try { $item = $pool->getItem($key); } catch (\Doctrine\Common\Cache\Psr6\InvalidArgument $e) { /* log and skip cache */ }

Prevention

When it happens

Trigger: Calling $pool->getItem($key), hasItem, deleteItem or deleteItems with a null, int, object (e.g. a key object or entity), float, or array instead of a string.

Common situations: Passing a user-supplied ID that is an integer from a database row; forgetting to cast/serialize a key; passing null from an unconfigured lookup; refactors where the key variable became an object.

Understand the failure class

Background: "must be a positive integer", "cannot be empty", "invalid argument": how invalid-argument errors work across open-source libraries — this error's family across 33 libraries.

Related errors


AI-assisted analysis of doctrine/cache@e0a9919443 (2026-09-13). Data as JSON: /api/errors/bfed45614d7747da. Report an issue: GitHub.

Appendix: source

Thrown at lib/Doctrine/Common/Cache/Psr6/CacheAdapter.php:257

        foreach ($byLifetime as $lifetime => $values) {
            $success = $this->doSaveMultiple($values, $lifetime) && $success;
        }

        return $success;
    }

    public function __destruct()
    {
        $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
    {

View on GitHub (pinned to e0a9919443)