Windows: stderr deadlock still possible — NonBlockingStderrHandler degrades to blocking writes (follow-up to #2044)
Preconditions:
- I have made sure it's an actual issue, not a question (use GitHub Discussions instead).
- I have actually encountered this issue in practice. Issues that are based on (AI-based) code analysis only will be closed without comment.
- I have consulted the user guide and verified that the issue cannot be resolved by adjusting configuration/following recommended workflows.
- I have looked for similar issues and discussions, including closed ones.
Issue details:
- I have provided a meaningful title and description.
- I have explained how the issue arose and, where possible, added instructions on how to reproduce it.
- I have added details on my setup: Serena version, MCP client, OS, the programming language(s), relevant configuration adjustments and project specifics.
- If the issue relates to an application of Serena to an open-source project, I have added the link.
This is a non-urgent follow-up issue. It tracks a known, documented platform limitation left out of #2044 on purpose — nothing in the current release regresses; the deadlock this issue describes is exactly the pre-existing behavior on Windows.
Follow-up to #2044
PR #2044 (fix(serena): non-blocking stderr handler to prevent logging deadlock in MCP servers) fixes the stderr logging deadlock observed in production on POSIX (see #1588 for the sibling symptom: executor thread wedged in logging.emit → stream write after the host failed to drain the stream). On Windows, however, the same deadlock scenario remains possible, and the PR ships it that way deliberately instead of emulating the missing mechanism with deprecated APIs. The limitation is documented in the handler's docstring and CHANGELOG, and analyzed for the maintainers in this PR comment.
Why Windows cannot get the same mechanism today
os.set_blockingdoes not exist on Windows (AttributeError), so the fd cannot be switched to non-blocking the POSIX way.fstaton Windows does not report anonymous pipes as FIFOs (stat.S_ISFIFOis false), so the handler cannot even detect the bounded-buffer case viast_mode.- There is no
O_NONBLOCKequivalent for anonymous pipes on Windows.
Consequence: NonBlockingStderrHandler degrades to plain blocking writes on Windows — identical to a plain StreamHandler. With an MCP client host that never drains the spawned server's stderr, the stderr buffer (a socketpair/pipe with a finite buffer) eventually fills and a write() blocks while holding the logging module's global lock, freezing every thread that logs — the same failure chain PR #2044 eliminates on POSIX.
Practical mitigation (why this is low urgency): the dominant Windows MCP client hosts redirect the server's stderr to a log file, which is an unbounded sink — the buffer never fills.
Proposed resolution (for the maintainers to decide)
SetNamedPipeHandleState(handle, PIPE_NOWAIT) via ctypes on the write end of an anonymous pipe does work: when the buffer is full, WriteFile fails immediately with ERROR_NO_DATA → Python raises OSError → the handler's existing except drops the record. That would honor the non-blocking contract on Windows too, and would let PR #2044's full-pipe tests run unskipped in the Windows CI job. It was not included in the PR because PIPE_NOWAIT is documented as deprecated by Microsoft and the PR did not want to build a bug-fix on deprecated functionality. The change would be a ~15-line Windows branch in _create_writer in src/serena/util/non_blocking_stderr_handler.py.
Alternatives to weigh: accept the documented limitation indefinitely, or emulate non-blocking behavior with a bounded retry loop (rejected during the PR review — it cannot avoid blocking without either dropping correctness or adding a writer thread, which PR #2044 deliberately avoids because a daemon writer deadlocks CPython's interpreter shutdown).
Setup
- Serena: current
main+ PR #2044 branch (fix/stderr-logging-deadlock, commits61ecac8aandf6ef7183) - OS: Windows (CI runners: windows-2025; the limitation also applies to user machines)
- MCP client: any Windows host that spawns
start-mcp-server/project-serverin stdio mode and does not drain stderr - Languages: not applicable (the deadlock is in Serena's own logging pipeline, independent of language servers)
Source: oraios/serena