python/cpython · error · RuntimeError

{func_name}() called while another coroutine is already wait

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.

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)

Solutions

  1. Ensure exactly one consumer coroutine per StreamReader; route all reads through that consumer (queue or dedicated reader task)
  2. Wrap reads in an asyncio.Lock if multiple tasks must read, so only one is inside a read call at a time
  3. For wait_for timeouts, cancel and await the inner read fully before retrying, rather than starting a parallel read
  4. 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

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


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/84e26d8261ecf971. Report an issue: GitHub.