symfony/symfony · critical · InvalidArgumentException
Redis connection failed
Error message
Redis connection failed: {error}. What it means
An InvalidArgumentException from the Redis cache adapter thrown when the underlying ext-redis or Relay connect()/pconnect() call did not establish a connection (isConnected() returned false), or when a subsequent $redis->select($dbindex) failed, or when the connection attempt raised a \RedisException / \Relay\Exception. The message embeds the specific low-level error extracted via the error handler or getLastError(). This is a runtime connectivity / authentication failure.
Solutions
- Read the embedded {error} text — it names the actual cause (Connection refused, NOAUTH, SELECT failed, etc.).
- Test connectivity directly: 'redis-cli -h <host> -p <port> -a <password> PING'.
- If NOAUTH: add credentials to the DSN: 'redis://:password@host:6379' or 'redis://user:password@host:6379' for ACL.
- If SELECT failed: lower the dbindex to a valid database number (default Redis ships 16 DBs, 0-15).
- For TLS errors on rediss://: provide ssl context options in the query string, e.g. '?ssl[verify_peer]=0' for self-signed or proper CA bundle paths.
- Increase timeout via '?timeout=5' if the cause is a slow network.
Example fix
// before
REDIS_URL=redis://redis-prod:6379
// error: Redis connection failed: (NOAUTH Authentication required.).
// after
REDIS_URL=redis://:${REDIS_PASSWORD}@redis-prod:6379 Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight connectivity test matching the DSN
function pingRedis(string $dsn, float $timeout = 2): void
{
$host = parse_url($dsn, PHP_URL_HOST);
$port = parse_url($dsn, PHP_URL_PORT) ?: 6379;
$scheme = parse_url($dsn, PHP_URL_SCHEME) ?? 'redis';
if ('rediss' === $scheme || 'valkeys' === $scheme) {
// TLS: skip raw fsockopen; use stream_socket_client with SSL
$remote = "tls://{$host}:{$port}";
} else {
$remote = "tcp://{$host}:{$port}";
}
$fp = @stream_socket_client($remote, $errNo, $errStr, $timeout);
if (!$fp) {
throw new \RuntimeException("Cannot reach Redis at {$host}:{$port}: {$errStr}");
}
fclose($fp);
} Try / catch
use Symfony\Component\Cache\Exception\InvalidArgumentException as CacheIA;
try {
$conn = RedisAdapter::createConnection($dsn);
} catch (CacheIA $e) {
if (str_starts_with($e->getMessage(), 'Redis connection failed')) {
// classify: NOAUTH -> prompt credentials, SELECT -> lower dbindex, refused -> ops alert
$msg = $e->getMessage();
match (true) {
str_contains($msg, 'NOAUTH') => /* rotate creds */ null,
str_contains($msg, 'SELECT') => /* check dbindex range */ null,
default => /* network/ops */ null,
};
}
throw $e;
} Prevention
- Store credentials in secrets (e.g. symfony/secret-vault), not plain env vars.
- Always run 'redis-cli ... PING' as part of deploy verification.
- Use TLS for cross-network Redis and pre-validate SSL context.
When it happens
Trigger: Redis server down or refusing connections; wrong port; AUTH failure (wrong password); SELECT failure (dbindex out of range e.g. SELECT 9999 on a Redis with 16 DBs); TLS/cert handshake failure for 'rediss://' DSNs; connection timeout because the host is unreachable; firewall dropping packets.
Common situations: Redis container not started in docker-compose; REDIS_URL points to a host that only resolves inside another network namespace; password rotated but DSN not updated; switching from redis:// to rediss:// without configuring SSL context; Redis configured with requirepass but DSN has no credentials.
Related errors
- Failed to retrieve master information from sentinel
- Cannot find the "redis" extension nor the "relay" extension…
- Cannot use both "cluster" and "sentinel" at the same time.
- Cannot use Redis Sentinel: class
- Invalid Redis DSN.
AI-assisted analysis of symfony/symfony@3b11ffbe25 (2026-08-11).
Data as JSON: /api/errors/f94f40a792f8e19a.
Report an issue: GitHub.
Appendix: source
Thrown at src/Symfony/Component/Cache/Traits/RedisTrait.php:333
try {
$extra = [
'stream' => self::filterSslOptions($params['ssl'] ?? []) ?: null,
];
if (null !== $params['auth']) {
$extra['auth'] = $params['auth'];
}
@$redis->{$connect}($host, $port, (float) $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...\defined('Redis::SCAN_PREFIX') || !$isRedisExt ? [$extra] : []);
set_error_handler(static function ($type, $msg) use (&$error) { $error = $msg; });
try {
$isConnected = $redis->isConnected();
} finally {
restore_error_handler();
}
if (!$isConnected) {
$error = preg_match('/^Redis::p?connect\(\): (.*)/', $error ?? $redis->getLastError() ?? '', $error) ? \sprintf(' (%s)', $error[1]) : '';
throw new InvalidArgumentException('Redis connection failed: '.$error.'.');
}
if (0 < $params['tcp_keepalive'] && (!$isRedisExt || \defined('Redis::OPT_TCP_KEEPALIVE'))) {
$redis->setOption($isRedisExt ? \Redis::OPT_TCP_KEEPALIVE : Relay::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']);
}
if (!$redis->select($params['dbindex'])) {
$e = preg_replace('/^ERR /', '', $redis->getLastError());
throw new InvalidArgumentException('Redis connection failed: '.$e.'.');
}
} catch (\RedisException|\Relay\Exception $e) {
throw new InvalidArgumentException('Redis connection failed: '.$e->getMessage());
}
return $redis;
};
if ($params['lazy']) {View on GitHub (pinned to 3b11ffbe25)