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
- Increase socket_connect_timeout to a value larger than realistic teardown time (e.g. 5-10s).
- Call disconnect(nowait=True) during forced shutdown to skip wait_closed() entirely.
- Ensure the event loop is still running when aclose() is awaited (avoid closing during loop shutdown).
- 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
- Set socket_connect_timeout to a realistic teardown budget (>=5s).
- Use disconnect(nowait=True) during forced shutdown.
- Avoid aclose() after the event loop is already closing.
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
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Timeout reading from
- Timeout writing to socket
- Connection closed by server.
- Error while writing to socket. .
- Error while reading from
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)