redis/redis-py · warning · TimeoutError

Timed out closing connection after

Error message

Timed out closing connection after {self.socket_connect_timeout}

What it means

Raised as TimeoutError inside disconnect() when the async_timeout(self.socket_connect_timeout) context wrapping the writer close/wait_closed expires. It means the TCP teardown (writer.wait_closed()) did not finish within the configured connect timeout, which the code reuses as the close deadline. The connection is forcibly torn down and the timeout is re-raised.

Solutions

  1. Increase socket_connect_timeout to a value larger than realistic teardown time (e.g. 5-10s).
  2. Call disconnect(nowait=True) during forced shutdown to skip wait_closed() entirely.
  3. Ensure the event loop is still running when aclose() is awaited (avoid closing during loop shutdown).
  4. Diagnose the network path for packet loss/black-holing between client and server.

Example fix

// before
r = redis.asyncio.Redis(host=h, socket_connect_timeout=0.5)
// after
r = redis.asyncio.Redis(host=h, socket_connect_timeout=5.0)
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

def is_close_timeout(exc: BaseException) -> bool:
    return isinstance(exc, TimeoutError) and 'closing connection' in str(exc).lower()

Try / catch

try:
    await client.aclose()
except TimeoutError:
    # graceful close stalled; force
    await client.connection_pool.disconnect(inuse_connections=True)

Prevention

When it happens

Trigger: Calling await client.aclose() (or connection.disconnect()) when the remote is unresponsive or the network is lossy enough that the FIN handshake stalls longer than socket_connect_timeout. Common during app shutdown while the server is under heavy load or already gone.

Common situations: Graceful shutdown racing with a dead peer (no RST returned); lossy NAT/firewall dropping FIN packets; very small socket_connect_timeout (sub-second) on a high-latency link; disconnect triggered from a finally block during event-loop teardown.

Understand the failure class

Related errors


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

Appendix: source

Thrown at redis/asyncio/connection.py:1106

            async with async_timeout(self.socket_connect_timeout):
                self._parser.on_disconnect()
                # Reset the reconnect flag
                self.reset_should_reconnect()
                if not self.is_connected:
                    return
                try:
                    self._writer.close()  # type: ignore[union-attr]
                    # wait for close to finish, except when handling errors and
                    # forcefully disconnecting.
                    if not nowait:
                        await self._writer.wait_closed()  # type: ignore[union-attr]
                except OSError:
                    pass
                finally:
                    self._reader = None
                    self._writer = None
        except asyncio.TimeoutError:
            raise TimeoutError(
                f"Timed out closing connection after {self.socket_connect_timeout}"
            ) from None

        if error:
            if health_check_failed:
                close_reason = CloseReason.HEALTHCHECK_FAILED
            else:
                close_reason = CloseReason.ERROR

            if failure_count is not None and failure_count > self.retry.get_retries():
                await record_error_count(
                    server_address=getattr(self, "host", None),
                    server_port=getattr(self, "port", None),
                    network_peer_address=getattr(self, "host", None),
                    network_peer_port=getattr(self, "port", None),
                    error_type=error,
                    retry_attempts=failure_count,
                )

View on GitHub (pinned to 6a6b581b48)