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
- Call communicate(input=...) exactly once per process; re-run the program in a NEW process for retries
- For incremental stdin writing, use proc.stdin.write()/drain() instead of communicate
- 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
- Call communicate() at most once per Process; re-spawn for retries
- Use proc.stdin.write()/drain() for incremental input instead of repeated communicate
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
- Failed to fetch glossary.json
- Unimplemented ioctl request
- profiling_trace: Placeholder pattern not found in {js_path.n
- offset must be a non-negative integer (got {!r})
- server_hostname is only meaningful with ssl
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/5c90110c18d60881.
Report an issue: GitHub.