{"record":{"id":"84e26d8261ecf971","repo":"python/cpython","slug":"func-name-called-while-another-coroutine-is-al","errorCode":null,"errorMessage":"{func_name}() called while another coroutine is already waiting for incoming data","messagePattern":"(.+?)\\(\\) called while another coroutine is already waiting for incoming data","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/streams.py","lineNumber":528,"sourceCode":"            except NotImplementedError:\n                # The transport can't be paused.\n                # We'll just have to buffer all data.\n                # Forget the transport so we don't keep trying.\n                self._transport = None\n            else:\n                self._paused = True\n\n    async def _wait_for_data(self, func_name):\n        \"\"\"Wait until feed_data() or feed_eof() is called.\n\n        If stream was paused, automatically resume it.\n        \"\"\"\n        # StreamReader uses a future to link the protocol feed_data() method\n        # to a read coroutine. Running two read coroutines at the same time\n        # would have an unexpected behaviour. It would not possible to know\n        # which coroutine would get the next data.\n        if self._waiter is not None:\n            raise RuntimeError(\n                f'{func_name}() called while another coroutine is '\n                f'already waiting for incoming data')\n\n        assert not self._eof, '_wait_for_data after EOF'\n\n        # Waiting for data while paused will make deadlock, so prevent it.\n        # This is essential for readexactly(n) for case when n > self._limit.\n        if self._paused:\n            self._paused = False\n            self._transport.resume_reading()\n\n        self._waiter = self._loop.create_future()\n        try:\n            await self._waiter\n        finally:\n            self._waiter = None\n\n    async def readline(self):","sourceCodeStart":510,"sourceCodeEnd":546,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/streams.py#L510-L546","documentation":"RuntimeError raised by StreamReader._wait_for_data when a second read coroutine starts while another is already suspended waiting for feed_data(). The reader uses a single _waiter future to link protocol callbacks to one read call, so two concurrent readers cannot be told apart and the state is rejected rather than silently corrupted.","triggerScenarios":"Two coroutines simultaneously call any of read(), readline(), readuntil(), readexactly(), or read(-1) on the same StreamReader while data is not yet available so both reach the waiting state; e.g. a timeout wrapper that spawns read() while an outer read() is still pending, or one task reading stdout while another reads it too.","commonSituations":"asyncio.wait_for(reader.readline(), ...) combined with a separately scheduled read task; multiple consumers 'sharing' a connection; a heartbeat task that reads occasionally while the main loop also reads; refactors that moved reads into a helper launched with create_task.","solutions":["Ensure exactly one consumer coroutine per StreamReader; route all reads through that consumer (queue or dedicated reader task)","Wrap reads in an asyncio.Lock if multiple tasks must read, so only one is inside a read call at a time","For wait_for timeouts, cancel and await the inner read fully before retrying, rather than starting a parallel read","Split the stream (e.g. tee via a queue fed by one reader) when several tasks need the data"],"exampleFix":"// before\nasync def worker(r):\n    line = await r.readline()   # two workers share r -> RuntimeError\n\n// after\nread_lock = asyncio.Lock()\nasync def worker(r):\n    async with read_lock:\n        line = await r.readline()","handlingStrategy":"validation","validationCode":"class SingleStreamReader:\n    def __init__(self, reader: asyncio.StreamReader):\n        self.reader = reader\n        self._lock = asyncio.Lock()\n    async def readline(self):\n        async with self._lock:\n            return await self.reader.readline()","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Enforce one consumer task per StreamReader in code review; make the owner explicit in design","Route all reads through a single accessor that holds an asyncio.Lock","Avoid wait_for around reads while another read of the same stream can be in flight"],"tags":["asyncio","streams","concurrency","single-consumer"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}