redis/redis-py · error · TimeoutError

Timeout writing to socket

Error message

Timeout writing to socket

What it means

Raised as a TimeoutError from send_packed_command() when self.socket_timeout is set and the write (writelines + drain) does not complete within that timeout. The connection is forcibly disconnected (nowait=True) before the error propagates, because a stuck write means the socket is unusable.

Source

Thrown at redis/asyncio/connection.py:1193

            await self.connect_check_health(check_health=False)
        if check_health:
            await self.check_health()

        try:
            if isinstance(command, str):
                command = command.encode()
            if isinstance(command, bytes):
                command = [command]
            if self.socket_timeout:
                await asyncio.wait_for(
                    self._send_packed_command(command), self.socket_timeout
                )
            else:
                self._writer.writelines(command)
                await self._writer.drain()
        except asyncio.TimeoutError:
            await self.disconnect(nowait=True)
            raise TimeoutError("Timeout writing to socket") from None
        except OSError as e:
            await self.disconnect(nowait=True)
            if len(e.args) == 1:
                err_no, errmsg = "UNKNOWN", e.args[0]
            else:
                err_no = e.args[0]
                errmsg = e.args[1]
            raise ConnectionError(
                f"Error {err_no} while writing to socket. {errmsg}."
            ) from e
        except BaseException:
            # BaseExceptions can be raised when a socket send operation is not
            # finished, e.g. due to a timeout.  Ideally, a caller could then re-try
            # to send un-sent data. However, the send_packed_command() API
            # does not support it so there is no point in keeping the connection open.
            await self.disconnect(nowait=True)
            raise

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Increase socket_timeout to accommodate the largest expected command/pipeline size and worst-case latency.
  2. Reduce the size of pipelines/batches or stream large values (e.g. SCAN) instead of sending them at once.
  3. Investigate server-side pauses (slowlog, latency monitor, DEBUG SLEEP left running, memory pressure).
  4. Verify network bandwidth and TCP window scaling between client and server.

Example fix

// before
r = redis.asyncio.Redis(host=h, port=p, socket_timeout=0.1)

// after
r = redis.asyncio.Redis(host=h, port=p, socket_timeout=5)
Defensive patterns

Strategy: retry

Validate before calling

def safe_socket_timeout(workload_seconds: float) -> float:
    # at least 2x the expected worst-case command time
    return max(1.0, workload_seconds * 2)

Try / catch

from redis.exceptions import TimeoutError, ConnectionError
for attempt in range(3):
    try:
        await r.execute_command(*big_cmd)
        break
    except TimeoutError as e:
        if "writing to socket" in str(e):
            await asyncio.sleep(2 ** attempt)
            continue
        raise

Prevention

When it happens

Trigger: Calling any command (send_command/send_packed_command) with socket_timeout configured, where the underlying writer.drain() blocks longer than socket_timeout. Happens when the server or network stops draining the TCP send buffer (slow consumer, full kernel buffers).

Common situations: Pipelining/transactions with very large payloads that saturate the receive window; a server under extreme load or paused (DEBUG SLEEP, GC stall, swap thrash); a network link with high latency loss causing TCP backoff; socket_timeout set too low for the workload.

Related errors


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