python/cpython · error · RuntimeError
() called while another coroutine is already waiting for…
Error message
{func_name}() called while another coroutine is already waiting for incoming data What it means
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.
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
Example fix
// before
async def worker(r):
line = await r.readline() # two workers share r -> RuntimeError
// after
read_lock = asyncio.Lock()
async def worker(r):
async with read_lock:
line = await r.readline() Defensive patterns
Strategy: validation
Validate before calling
class SingleStreamReader:
def __init__(self, reader: asyncio.StreamReader):
self.reader = reader
self._lock = asyncio.Lock()
async def readline(self):
async with self._lock:
return await self.reader.readline() Type guard
null
Try / catch
null
Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Connection lost
- d3-flame-graph library failed to load
- Empty waiter is already set
- Limit cannot be <= 0
- Passing coroutines is forbidden, use tasks explicitly.
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/84e26d8261ecf971.
Report an issue: GitHub.
Appendix: source
Thrown at Lib/asyncio/streams.py:528
except NotImplementedError:
# The transport can't be paused.
# We'll just have to buffer all data.
# Forget the transport so we don't keep trying.
self._transport = None
else:
self._paused = True
async def _wait_for_data(self, func_name):
"""Wait until feed_data() or feed_eof() is called.
If stream was paused, automatically resume it.
"""
# StreamReader uses a future to link the protocol feed_data() method
# to a read coroutine. Running two read coroutines at the same time
# would have an unexpected behaviour. It would not possible to know
# which coroutine would get the next data.
if self._waiter is not None:
raise RuntimeError(
f'{func_name}() called while another coroutine is '
f'already waiting for incoming data')
assert not self._eof, '_wait_for_data after EOF'
# Waiting for data while paused will make deadlock, so prevent it.
# This is essential for readexactly(n) for case when n > self._limit.
if self._paused:
self._paused = False
self._transport.resume_reading()
self._waiter = self._loop.create_future()
try:
await self._waiter
finally:
self._waiter = None
async def readline(self):View on GitHub (pinned to bc6749cc3b)