redis/redis-py · error · ConnectionError

protocol must be either 2 or 3

Error message

protocol must be either 2 or 3

What it means

ConnectionError from the async Connection constructor (redis/asyncio/connection.py:703) when the parsed integer protocol is outside the supported range (only 2 or 3 are valid). RESP 1 is obsolete and RESP >3 does not exist, so any other integer is rejected up front.

Solutions

  1. Use protocol=3 (current default) or protocol=2
  2. Leave protocol unset to accept the default
  3. Fix the upstream config value

Example fix

// before
Redis(protocol=4)
// after
Redis(protocol=3)
Defensive patterns

Strategy: validation

Validate before calling

if protocol not in (2, 3):
    raise ValueError('protocol must be 2 or 3')

Prevention

When it happens

Trigger: `Redis(protocol=1)`, `Redis(protocol=4)`, `Redis(protocol=0)`.

Common situations: Misconfigured protocol env var set to an unsupported value; assuming a newer RESP version exists.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/170de481b66b5878. Report an issue: GitHub.

Appendix: source

Thrown at redis/asyncio/connection.py:704

        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()

        AsyncMaintNotificationsAbstractConnection.__init__(
            self,
            maint_notifications_config,

View on GitHub (pinned to 6a6b581b48)