redis/redis-py · error · ValueError

"max_connections" must be a positive integer

Error message

"max_connections" must be a positive integer

What it means

Raised by ConnectionPool.__init__ when max_connections is not an int or is negative. Note the guard checks isinstance int and < 0 (0 is allowed because the line above coerces falsy values to 100). A non-integer (e.g., a string from a URL/env var) or a negative number fails the check. The default when None/0/falsy is 100.

Source

Thrown at redis/asyncio/connection.py:2627

        ``ValueError`` to be raised. Once parsed, the querystring arguments
        and keyword arguments are passed to the ``ConnectionPool``'s
        class initializer. In the case of conflicting arguments, querystring
        arguments always win.
        """
        url_options = parse_url(url)
        kwargs.update(url_options)
        return cls(**kwargs)

    def __init__(
        self,
        connection_class: Type[AbstractConnection] = Connection,
        max_connections: Optional[int] = None,
        maint_notifications_config: MaintNotificationsConfig | None = None,
        **connection_kwargs,
    ):
        max_connections = max_connections or 100
        if not isinstance(max_connections, int) or max_connections < 0:
            raise ValueError('"max_connections" must be a positive integer')

        self.connection_class = connection_class
        self._connection_kwargs = connection_kwargs
        self.max_connections = max_connections

        # Resolve the HIMPORT registry. A pre-built ``himport_registry`` (shared, e.g.
        # from the cluster client) takes precedence; otherwise build a fresh empty one.
        # A registry always exists so runtime ``himport_prepare`` mutates a single object
        # every connection already shares. The object stays in ``connection_kwargs`` so
        # it reaches every connection. It is injected unconditionally (like other
        # auto-added pool kwargs), so a custom ``connection_class`` must accept
        # ``**kwargs`` (or a ``himport_registry`` parameter), as built-ins do.
        himport_registry = connection_kwargs.get("himport_registry")
        if himport_registry is None:
            himport_registry = HImportRegistry()
            connection_kwargs["himport_registry"] = himport_registry
        self.himport_registry = himport_registry

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Coerce max_connections to int explicitly before passing it: int(os.environ['MAX_CONN']).
  2. Ensure the value is a positive integer (>= 0; 0/None becomes the default 100).
  3. Validate the value at the boundary where you read configuration, not at pool construction.

Example fix

// before
pool = ConnectionPool(max_connections=os.environ['REDIS_MAX_CONN'])
// after
pool = ConnectionPool(max_connections=int(os.environ['REDIS_MAX_CONN']))
Defensive patterns

Strategy: type-guard

Validate before calling

def coerce_max_connections(v):
    v = int(v)
    if v < 0:
        raise ValueError('max_connections must be >= 0')
    return v or 100

pool = ConnectionPool(max_connections=coerce_max_connections(os.environ.get('REDIS_MAX_CONN', 100)))

Type guard

def is_valid_max_connections(v) -> bool:
    return isinstance(v, int) and not isinstance(v, bool) and v >= 0

Try / catch

try:
    pool = ConnectionPool(max_connections=raw)
except ValueError as e:
    if 'max_connections' in str(e):
        raw = int(raw); pool = ConnectionPool(max_connections=raw)\n    else:\n        raise

Prevention

When it happens

Trigger: Passing max_connections as a non-int (string '50', float 50.0, or None-coerced-but-still-wrong value) or a negative int to ConnectionPool, Redis(connection_pool=...) or via a URL with max_connections in the query string that parses to a string. The check at connection.py:2626 runs before the pool is usable.

Common situations: Reading max_connections from an environment variable or config file as a string and passing it unconverted; passing a float; off-by-one or sign errors computing pool size; URL parsing where the value is a str until coerced elsewhere.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/866cff0b279d0bd1.json. Report an issue: GitHub.