redis/redis-py · error · ConnectionError
protocol must be either 2 or 3
Error message
protocol must be either 2 or 3
What it means
Raised in AbstractConnection.__init__ (connection.py:928-929) after int(protocol) succeeds but the value is outside the supported range [2,3]. redis-py only speaks RESP2 and RESP3, so any other integer (1, 4, 0, -1) is rejected. This guards against silently negotiating an unsupported wire version.
Solutions
- Use protocol=2 or protocol=3 (3 is the current default).
- Validate config at load time: if proto not in (2,3): raise/bound to 3.
- Upgrade redis-py if you genuinely need a newer RESP version that may have shipped.
Example fix
# before r = redis.Redis(host=h, port=p, protocol=4) # after r = redis.Redis(host=h, port=p, protocol=3)
Defensive patterns
Strategy: validation
Validate before calling
PROTO = int(proto) if proto is not None else 3
assert PROTO in (2, 3), f'protocol must be 2 or 3, got {PROTO}'
r = redis.Redis(host=h, port=p, protocol=PROTO) Type guard
def is_supported_resp(p) -> bool:
try:
return int(p) in (2, 3)
except (TypeError, ValueError):
return False Try / catch
from redis.exceptions import ConnectionError
try:
r = redis.Redis(host=h, port=p, protocol=proto)
except ConnectionError as e:
if 'either 2 or 3' in str(e):
r = redis.Redis(host=h, port=p, protocol=3)
else:
raise Prevention
- Bound protocol to {2,3} at the config layer.
- Add a unit test asserting your config loader never emits out-of-range values.
When it happens
Trigger: Passing protocol=1, protocol=4, protocol=0, or any integer not equal to 2 or 3 to redis.Redis/Connection.
Common situations: Typo (protocol=4); arithmetic/config drift producing an out-of-range number; assuming a newer RESP version exists before upgrading the library.
Related errors
- protocol must be an integer
- Cache must implement CacheInterface
- Client caching is only supported with RESP version 3
- Error setting client name
- Invalid Database
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/673647ddf8f57c52.
Report an issue: GitHub.
Appendix: source
Thrown at redis/connection.py:929
self.health_check_interval = health_check_interval
self.next_health_check = 0
self.redis_connect_func = redis_connect_func
self.encoder = Encoder(encoding, encoding_errors, decode_responses)
self.handshake_metadata = None
self._sock = None
self._socket_read_size = socket_read_size
self._connect_callbacks = []
self._buffer_cutoff = 6000
self._re_auth_token: Optional[TokenInterface] = None
try:
p = int(protocol)
except TypeError:
p = DEFAULT_RESP_VERSION
except ValueError:
raise ConnectionError("protocol must be an integer")
else:
if p < 2 or p > 3:
raise ConnectionError("protocol must be either 2 or 3")
self.protocol = p
self.legacy_responses = legacy_responses
if self.protocol == 3 and parser_class == _RESP2Parser:
# If the protocol is 3 but the parser is RESP2, change it to RESP3
# This is needed because the parser might be set before the protocol
# or might be provided as a kwarg to the constructor
# We need to react on discrepancy only for RESP2 and RESP3
# as hiredis supports both
parser_class = _RESP3Parser
self.set_parser(parser_class)
self._command_packer = self._construct_command_packer(command_packer)
self._should_reconnect = False
# HIMPORT client-side state. `himport_registry` is the shared client-level
# registry (empty if unconfigured) and persists across reconnects.
self.himport_registry = himport_registry
self._reset_himport_state()View on GitHub (pinned to 6a6b581b48)