python/cpython · error · ValueError

Cannot send input after starting communication

Error message

Cannot send input after starting communication

What it means

ValueError raised by asyncio.subprocess.Process.communicate() when it is called a second (or later) time with a non-empty input while _communication_started is already true. Input can only be fed to stdin once, on the first communicate() call; later calls may only reap output with input=None.

Source

Thrown at Lib/asyncio/subprocess.py:201

            assert fd == 1
            stream = self.stdout
            buf = self._stdout_buf
        if self._loop.get_debug():
            name = 'stdout' if fd == 1 else 'stderr'
            logger.debug('%r communicate: read %s', self, name)
        # Append each block to the persistent buffer as soon as it is
        # read so that no output is lost if this coroutine is cancelled.
        while block := await stream.read(stream._limit):
            buf += block
        if self._loop.get_debug():
            name = 'stdout' if fd == 1 else 'stderr'
            logger.debug('%r communicate: close %s', self, name)
        transport.close()

    async def communicate(self, input=None):
        if self._communication_started:
            if input:
                raise ValueError(
                    "Cannot send input after starting communication")
        else:
            self._input = input
            self._communication_started = True
        if self.stdin is not None:
            stdin = self._feed_stdin(self._input)
        else:
            stdin = self._noop()
        if self.stdout is not None:
            stdout = self._read_stream(1)
        else:
            stdout = self._noop()
        if self.stderr is not None:
            stderr = self._read_stream(2)
        else:
            stderr = self._noop()
        await tasks.gather(stdin, stdout, stderr)
        await self.wait()

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Call communicate(input=...) exactly once per process; re-run the program in a NEW process for retries
  2. For incremental stdin writing, use proc.stdin.write()/drain() instead of communicate
  3. Subsequent output collection on the same process must use communicate() with no input, or read from proc.stdout directly

Example fix

// before
out = await proc.communicate(input=payload)
if retry_needed:
    out = await proc.communicate(input=payload)  # ValueError

// after
out = await proc.communicate(input=payload)
if retry_needed:
    proc = await asyncio.create_subprocess_exec(*cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
    out = await proc.communicate(input=payload)
Defensive patterns

Strategy: validation

Validate before calling

async def communicate_once(proc, input_=None):
    if proc.returncode is not None:
        raise RuntimeError('process already finished; create a new one')
    return await proc.communicate(input_)

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: await proc.communicate(input=data) followed by another await proc.communicate(input=more) on the same Process object; commonly a retry loop or a wrapper that calls communicate both for setup and teardown of the same process.

Common situations: Retry-after-timeout logic that calls communicate() again with the same input on the same (now-exhausted) process; mixed usage where one code path already drained the process with communicate() and another feeds more stdin later; porting subprocess.run-style code that loops.

Related errors


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