symfony/symfony · error · Symfony\Component\Cache\Exception\InvalidArgumentException
Redis connection failed: {message}
Error message
Redis connection failed: {message} What it means
Thrown when the phpredis \Redis (or Relay) client raises a \RedisException / \Relay::Exception during the actual connect/open attempt in Symfony's Redis adapter initializer (RedisTrait.php:344-346). Symfony wraps the raw driver exception so the underlying message (connection refused, auth failed, DNS error, timeout) is preserved while normalizing it as an InvalidArgumentException. For non-lazy DSNs it fires at createConnection() time; for lazy DSNs it is deferred to the first cache operation.
Source
Thrown at src/Symfony/Component/Cache/Traits/RedisTrait.php:345
$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']) {
$redis = $isRedisExt ? RedisProxy::createLazyProxy($initializer) : RelayProxy::createLazyProxy($initializer);
} else {
$redis = $initializer();
}
} elseif (is_a($class, \RedisArray::class, true)) {
foreach ($hosts as $i => $host) {
$hosts[$i] = match ($host['scheme']) {
'tcp' => $host['host'].':'.$host['port'],
'tls' => 'tls://'.$host['host'].':'.$host['port'],
default => $host['path'],
};
}View on GitHub (pinned to 698e28026c)
Solutions
- Verify reachability: run 'redis-cli -h <host> -p <port> -a <pass> ping' (or with --user for ACL) and confirm you get PONG.
- Correct the DSN scheme/auth: 'redis://user:password@host:port/db' (ACL) or 'redis://:password@host' (legacy requirepass); use 'rediss://' only for TLS endpoints.
- Ensure the Redis service is up and the port is open between the app host and Redis (security groups, Docker network, k8s Service).
- For lazy pools, set 'lazy: false' during a deployment smoke test to surface connect errors at boot instead of on first request.
- Raise timeout/read_timeout in the DSN query string only after confirming connectivity (e.g. '?timeout=2&read_timeout=2').
Example fix
// before $dsn = 'redis://localhost:6379'; // fails: server on another host / needs auth $pool = RedisAdapter::createConnection($dsn); // after $dsn = 'redis://appuser:s3cret@redis.internal:6379/0'; // validate first $pool = RedisAdapter::createConnection($dsn, ['lazy' => false]);
Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight reachability before handing the DSN to the adapter
function redisDsnOk(string $dsn, float $timeout = 1): bool {
$u = parse_url($dsn);
if (!isset($u['host'], $u['port'])) return false;
$errno = 0; $errstr = '';
$fp = @fsockopen($u['host'], $u['port'], $errno, $errstr, $timeout);
if (!is_resource($fp)) return false;
fclose($fp);
return true;
}
if (!redisDsnOk($dsn)) { /* fall back / alert */ } Try / catch
// wrap the connection build; retry transient network errors with backoff
use Symfony\Component\Cache\Exception\InvalidArgumentException;
$attempt = 0;
do {
try {
$conn = RedisAdapter::createConnection($dsn, ['lazy' => false]);
break;
} catch (InvalidArgumentException $e) {
if (++$attempt >= 3 || !str_contains($e->getMessage(), 'connection')) { throw $e; }
usleep(200_000 * $attempt);
}
} while (true); Prevention
- Validate the DSN host/port with a socket connect test in a deploy smoke step.
- Keep Redis credentials in secrets/env, not hardcoded DSNs, so they match across envs.
- Run a 'bin/console cache:pool:prune' or a ping against each cache pool after deploy.
- Set 'lazy: false' in non-prod so connect errors surface at boot.
When it happens
Trigger: Calling RedisAdapter::createConnection('redis://host:6379') or building a Redis-backed cache/session/lock pool when $redis->{connect|pconnect}(...) throws. Concretely: server unreachable, AUTH/requirepass mismatch, invalid ACL user, wrong dbindex select, TLS handshake failure, or read_timeout exceeded during open.
Common situations: Redis not running in local dev; wrong host/port in cache DSN; password set on server but missing/wrong in DSN; firewall/security group blocking 6379; connecting with 'rediss://' (TLS) to a non-TLS port; Redis 6 ACLs requiring a username but DSN uses 'redis://:pass@host'.
Related errors
- Unsupported connection: "%s".
- Unsupported Predis cluster connection: only "%s" is, "%s" gi
- redis compression must be disabled when using "%s", use "%s"
- Redis maxmemory-policy setting "%s" is *not* supported by Re
- Failed to retrieve master information from sentinel "%s".
AI-assisted analysis of symfony/symfony@698e28026c (2026-08-06).
Data as JSON: /api/errors/a6de6cbc034ef33c.
Report an issue: GitHub.