langchain-ai/deepagents · error · BrokenPipeError
Hook process stdin is unavailable
Error message
Hook process stdin is unavailable
What it means
`_write_input` sends the serialized hook payload to the subprocess stdin. If `process.stdin` is None, it raises `BrokenPipeError` because there is no writable pipe to deliver the payload through. This is a defensive check inside the writer task spawned by `_communicate_bounded`.
Source
Thrown at libs/code/deepagents_code/hooks/runner.py:247
await stdin_task
except BaseException:
stdin_task.cancel()
stdout_task.cancel()
stderr_task.cancel()
await asyncio.gather(
stdin_task,
stdout_task,
stderr_task,
return_exceptions=True,
)
raise
return stdout[0], stderr[0], stdout[1], stderr[1]
async def _write_input(process: Process, payload: bytes) -> None:
if process.stdin is None:
msg = "Hook process stdin is unavailable"
raise BrokenPipeError(msg)
process.stdin.write(payload)
await process.stdin.drain()
process.stdin.close()
async def _read_bounded(
stream: asyncio.StreamReader,
limit: int,
) -> tuple[bytes, bool]:
retained = bytearray()
truncated = False
while chunk := await stream.read(_READ_CHUNK_BYTES):
remaining = limit - len(retained)
if remaining > 0:
retained.extend(chunk[:remaining])
if len(chunk) > remaining:
truncated = True
return bytes(retained), truncatedView on GitHub (pinned to a1af029e6e)
Solutions
- Spawn the hook process with `stdin=asyncio.subprocess.PIPE` so stdin is writable
- Communicate with the process exactly once — do not close stdin or call another communicate before `_write_input` runs
- Guard custom code paths: check `process.stdin is not None` before attempting to write
Example fix
// before proc = await asyncio.create_subprocess_exec(*argv) # stdin inherited // after proc = await asyncio.create_subprocess_exec(*argv, stdin=asyncio.subprocess.PIPE, stdout=PIPE, stderr=PIPE)
Defensive patterns
Strategy: try-catch
Validate before calling
if proc.stdin is None:
raise BrokenPipeError("hook subprocess was not created with stdin=PIPE") Type guard
def writable_stdin(p: asyncio.subprocess.Process) -> bool:
return p.stdin is not None and not p.stdin.is_closing() Try / catch
try:
await _communicate_bounded(proc, payload, limit)
except BrokenPipeError as e:
logger.error("cannot write hook payload: %s", e)
proc.kill() Prevention
- Create the process with stdin=asyncio.subprocess.PIPE
- Never close stdin or call communicate twice before the payload is written
- Assert pipe availability before spawning writer tasks
When it happens
Trigger: The hook subprocess was created without `stdin=PIPE` or its stdin was already closed/consumed, so `process.stdin` is None when `_communicate_bounded` schedules `_write_input` to send the payload.
Common situations: Subprocess created with inherited stdin or devnull; reusing a Process whose stdin was already closed by a prior communicate call; custom runner wiring that closes stdin before writing.
Related errors
- Hook process pipes are unavailable
- Server process exited with code {process.returncode}
- Server process is not running
- Server process exited with code {self._process.returncode}
- Permission interrupted by hook
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/a4e303b10b226f64.
Report an issue: GitHub.