redis/redis-py · error · ConnectionError
protocol must be an integer
Error message
protocol must be an integer
What it means
ConnectionError from the async Connection constructor (redis/asyncio/connection.py:701) when int(protocol) raises ValueError - i.e. protocol is a non-numeric string. The protocol argument must be coercible to an integer (2 or 3). A non-numeric value is rejected early rather than failing later during HELLO negotiation.
Solutions
- Pass an integer: Redis(protocol=3)
- Validate/convert config strings to int before passing: int(os.environ['REDIS_PROTOCOL'])
- Leave protocol unset to use the library default (DEFAULT_RESP_VERSION=3)
Example fix
// before
Redis(protocol=os.environ.get('REDIS_PROTOCOL', '3'))
// after
Redis(protocol=int(os.environ.get('REDIS_PROTOCOL', 3))) Defensive patterns
Strategy: validation
Validate before calling
try:
protocol = int(protocol)
except (TypeError, ValueError):
protocol = 3 # or raise a clear config error Prevention
- Coerce protocol to int from any string config source
- Leave protocol unset to use the default when unsure
When it happens
Trigger: `Redis(protocol='three')`, `Redis(protocol='2.7')` (float-string), or any protocol value that int() cannot parse.
Common situations: Reading protocol from an env var or config file as a string typo; passing the string form of the version.
Related errors
- protocol must be either 2 or 3
- Invalid RESP version
- Invalid SSL Certificate Requirements Flag
- Invalid ssl verify flag
- Invalid value for ' ' in connection URL.
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/944430898c6d862f.
Report an issue: GitHub.
Appendix: source
Thrown at redis/asyncio/connection.py:701
self.health_check_interval = health_check_interval
self.next_health_check: float = -1
self.encoder = encoder_class(encoding, encoding_errors, decode_responses)
self.redis_connect_func = redis_connect_func
self._reader: Optional[asyncio.StreamReader] = None
self._writer: Optional[asyncio.StreamWriter] = None
self._socket_read_size = socket_read_size
self._active_read_timeout = None
self._connect_callbacks: List[weakref.WeakMethod[ConnectCallbackT]] = []
self._buffer_cutoff = 6000
self._re_auth_token: Optional[TokenInterface] = None
self._should_reconnect = False
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 parser_class != _AsyncHiredisParser:
# The Python parsers are protocol-specific; hiredis supports both.
if self.protocol == 3 and parser_class == _AsyncRESP2Parser:
parser_class = _AsyncRESP3Parser
elif self.protocol == 2 and parser_class == _AsyncRESP3Parser:
parser_class = _AsyncRESP2Parser
self.set_parser(parser_class)
# 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)