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
- Cast or build the key as a string before calling the pool, e.g. (string) $id or 'user_' . $id
- If the key is an object, derive a string from it (e.g. ->getId() or serialize/md5 of a stable representation)
- Guard with is_string($key) before calling the adapter and handle invalid input at the boundary
- 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
- Always build cache keys via a single helper that enforces string keys
- Cast database IDs to string at the boundary
- Never pass raw user/config values straight into pool methods
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
- 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…
- Expected $time to be either an integer, an instance of…
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)