redis/redis-py · error · ValueError
"max_connections" must be a positive integer
Error message
"max_connections" must be a positive integer
What it means
The async ConnectionPool validates max_connections at construction: max_connections is first coerced via 'or 100' (so 0/None become 100), then if the result is not an int or is negative it raises ValueError. A string, float, bool, or negative number trips it. Note the bound is < 0, so 0 itself does not raise (it becomes 100).
Solutions
- Pass an int (typically > 0) for max_connections.
- Cast config/env values with int(...) before constructing the pool.
- Validate the value's type and sign in your own config loader.
Example fix
# before pool = ConnectionPool(max_connections=os.environ['MAX_CONN']) # after pool = ConnectionPool(max_connections=int(os.environ['MAX_CONN']))
Defensive patterns
Strategy: validation
Validate before calling
if not isinstance(max_connections, int) or isinstance(max_connections, bool) or max_connections < 0:
raise ValueError('max_connections must be a non-negative int')
max_connections = max_connections or 100 Type guard
def is_valid_max_connections(v) -> bool:
return isinstance(v, int) and not isinstance(v, bool) and v >= 0 Prevention
- Cast env/config-sourced values with int(...) at the config boundary.
- Reject floats and strings for pool size in your config loader.
When it happens
Trigger: Passing max_connections='10' (string from env/config), max_connections=-1, max_connections=3.5 (float), or max_connections=True/False to ConnectionPool.
Common situations: Reading max_connections from an environment variable or YAML/JSON config as a string without casting; float values from computed config; passing a sentinel that is not an int.
Related errors
- Invalid SSL Certificate Requirements Flag
- Invalid ssl verify flag
- Invalid value for ' ' in connection URL.
- Maintenance notifications are not supported for connection…
- Maintenance notifications are not supported for connections…
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/866cff0b279d0bd1.
Report an issue: GitHub.
Appendix: source
Thrown at redis/asyncio/connection.py:2630
``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 6a6b581b48)