fix(pty): don't stop relay on bare POLLHUP/POLLERR without POLLIN#54
Merged
Conversation
handle_pty_poll_events previously triggered proxy_master_to_client on any combination of POLLIN|POLLHUP|POLLERR|POLLNVAL. When POLLHUP or POLLERR fired without POLLIN (e.g. transiently during Node.js TTY reinitialisation at Claude Code startup), read() returned EIO, which proxy_master_to_client mapped to Closed, tearing down the relay while the child was still alive. For interactive TUIs the startup-timeout safety net is disabled, so nothing recovered the relay — causing an indefinite hang. Fix: only relay data (and stop on Closed/EOF) when POLLIN is set. Bare POLLHUP/POLLERR/POLLNVAL without POLLIN are now ignored; the waitpid path in the caller detects child exit instead.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
handle_pty_poll_eventstriggeredproxy_master_to_clienton any ofPOLLIN|POLLHUP|POLLERR|POLLNVAL. WhenPOLLHUPorPOLLERRfired withoutPOLLIN— which happens transiently during interactive TUI startup (e.g. Node.js reinitialising its TTY at Claude Code launch) —read()returnedEIO.proxy_master_to_client_oncemaps any read error toMasterProxyOutcome::Closed, causing the relay loop to stop while the child process was still alive. The startup-timeout safety net is disabled for interactive TUIs, so nothing recovered the relay → indefinite hang.Reported in: DataDog/shadowfax#421
Fix
Only relay data (and stop on
Closed/EOF) whenPOLLINis set. BarePOLLHUP/POLLERR/POLLNVALwithoutPOLLINare now ignored inhandle_pty_poll_events; thewaitpidpath in the caller detects child exit instead of relying on PTY master HUP.