{"record":{"id":"cd7147f89f16e38d","repo":"redis/redis-py","slug":"connection-has-data","errorCode":null,"errorMessage":"Connection has data","messagePattern":"Connection has data","errorType":"exception","errorClass":"ConnectionError","httpStatus":null,"severity":"error","filePath":"redis/asyncio/connection.py","lineNumber":2876,"sourceCode":"            decode_responses=kwargs.get(\"decode_responses\", False),\n        )\n\n    def make_connection(self):\n        \"\"\"Create a new connection.  Can be overridden by child classes.\"\"\"\n        # Note: We don't record IDLE here because async uses a sync make_connection\n        # but async record_connection_count. The recording is handled in get_connection.\n        return self.connection_class(**self.connection_kwargs)\n\n    async def ensure_connection(self, connection: AbstractConnection):\n        \"\"\"Ensure that the connection object is connected and valid\"\"\"\n        await connection.connect()\n        # connections that the pool provides should be ready to send\n        # a command. if not, the connection was either returned to the\n        # pool before all data has been read or the socket has been\n        # closed. either way, reconnect and verify everything is good.\n        try:\n            if await connection.can_read() and not self.maint_notifications_enabled():\n                raise ConnectionError(\"Connection has data\") from None\n        except (ConnectionError, TimeoutError, OSError):\n            await connection.disconnect()\n            await connection.connect()\n            if await connection.can_read() and not self.maint_notifications_enabled():\n                raise ConnectionError(\"Connection not ready\") from None\n\n    async def release(self, connection: AbstractConnection):\n        \"\"\"Releases the connection back to the pool\"\"\"\n        # Connections should always be returned to the correct pool,\n        # not doing so is an error that will cause an exception here.\n        async with self._lock:\n            self._in_use_connections.remove(connection)\n\n            if connection.should_reconnect():\n                await connection.disconnect()\n\n            self._available_connections.append(connection)\n","sourceCodeStart":2858,"sourceCodeEnd":2894,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/asyncio/connection.py#L2858-L2894","documentation":"When the pool hands out a connection, ensure_connection checks can_read(); if unread bytes are already on the socket and maintenance notifications are not enabled, it raises ConnectionError('Connection has data') to avoid a protocol desync. This signals a previous command left the socket dirty. The pool then disconnects/reconnects and re-checks, raising 'Connection not ready' only if data persists.","triggerScenarios":"A connection returned to the pool with unread bytes (a cancelled asyncio task mid-command, an abandoned pipeline/MULTI, or unparsed server data); the next ensure_connection sees data on the reused socket.","commonSituations":"Cancelled tasks that abort a command mid-flight; partial transactions; custom parser bugs; server pushing data the client never read.","solutions":["Let the pool self-heal: it disconnects and reconnects, so a retry of the operation usually succeeds.","Avoid abandoning commands/pipelines mid-flight (let MULTI/EXEC and pipelines complete).","If it recurs, investigate a protocol desync, a misbehaving proxy, or a buggy custom parser."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from redis.exceptions import ConnectionError\nfor attempt in range(retries):\n    try:\n        return await client.get(key)\n    except ConnectionError as e:\n        if 'Connection has data' not in str(e):\n            raise\n        await asyncio.sleep(backoff(attempt))\nraise","preventionTips":["Let commands/pipelines/MULTI complete instead of cancelling mid-flight.","Rely on the pool's automatic reconnect; transient 'has data' usually clears on retry."],"tags":["connection","protocol","transient","async"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}