redis/redis-py · error · ConnectionError

No connection available.

Error message

No connection available.

What it means

Raised as ConnectionError('No connection available.') by BlockingConnectionPool.get_connection when the underlying Queue.get(block=True, timeout=self.timeout) raises Empty — i.e. no connection became available within the configured timeout. BlockingConnectionPool uses a bounded queue and waits up to self.timeout seconds before giving up; unlike the default pool it does not error immediately at the cap, but it does error if nothing frees up in time.

Solutions

  1. Increase max_connections or self.timeout to match expected hold times.
  2. Fix connection leaks — always return connections; prefer the high-level Redis client which manages release for you.
  3. Cap concurrency (thread/async pool size) to stay within the Redis pool size.
  4. Shorten or remove long-running blocking commands, or dedicate a separate pool/client for pubsub and blocking calls.

Example fix

# before
pool = BlockingConnectionPool(max_connections=10, timeout=2)  # raises under load
# after
pool = BlockingConnectionPool(max_connections=50, timeout=20)
Defensive patterns

Strategy: retry

Validate before calling

# Pre-check: ensure expected concurrency <= pool size before relying on the pool.
if expected_concurrent_ops > pool.max_connections:
    raise RuntimeError(f'Concurrency {expected_concurrent_ops} exceeds pool size {pool.max_connections}; raise max_connections or reduce fan-out')

Try / catch

import time
from redis.exceptions import ConnectionError

for attempt in range(4):
    try:
        return r.get('key')
    except ConnectionError as e:
        if 'No connection available' in str(e) and attempt < 3:
            time.sleep(0.2 * (2 ** attempt))
            continue
        raise  # raise so the caller can shed load or alert

Prevention

When it happens

Trigger: All max_connections of a BlockingConnectionPool are checked out longer than self.timeout (default DEFAULT_TIMEOUT=20s). Connection leaks, long-running blocking commands, or saturated pubsub listeners holding all slots.

Common situations: Blocking commands (BLPOP, BRPOP, WAIT, MONITOR) tying up every connection. Thread/async fan-out exceeding pool size. Leaked connections never released. timeout set too low for the workload.

Related errors


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

Appendix: source

Thrown at redis/connection.py:3714

        """
        start_time_acquired = time.monotonic()
        # Make sure we haven't changed process.
        self._checkpid()
        is_created = False

        # Try and get a connection from the pool. If one isn't available within
        # self.timeout then raise a ``ConnectionError``.
        connection = None
        try:
            if self._in_maintenance:
                self._lock.acquire()
                self._locked = True
            try:
                connection = self.pool.get(block=True, timeout=self.timeout)
            except Empty:
                # Note that this is not caught by the redis client and will be
                # raised unless handled by application code. If you want never to
                raise ConnectionError("No connection available.")

            # If the ``connection`` is actually ``None`` then that's a cue to make
            # a new connection to add to the pool.
            if connection is None:
                # Start timing for observability
                start_time_created = time.monotonic()
                connection = self.make_connection()
                is_created = True
        finally:
            if self._locked:
                try:
                    self._lock.release()
                except Exception:
                    pass
                self._locked = False

        # Record state transition: IDLE -> USED
        # (make_connection already recorded IDLE +1 for new connections)

View on GitHub (pinned to 6a6b581b48)