Summary
On Windows, uvx code-review-graph@latest daemon status consistently raises OSError: [WinError 87] The parameter is incorrect even when the daemon's watcher PIDs are alive and the daemon is otherwise healthy. The status command is therefore unreliable as a health check on Windows.
Repro
- Start the daemon:
uvx code-review-graph@latest daemon start (succeeds; watchers spawn)
- Verify watchers are alive: PowerShell
Get-Process -Id <pid> returns the process for each PID in ~/.code-review-graph/daemon-state.json
- Query status:
uvx code-review-graph@latest daemon status
- Observed:
OSError: [WinError 87] The parameter is incorrect
- Expected: status report of running daemon
Root cause hypothesis
This appears to be a known CPython asyncio Proactor handle-close issue family:
PipeHandle.close() is not idempotent at the Win32 level — it calls _winapi.CloseHandle unconditionally, and if the underlying handle has already been closed between read_handle and CloseHandle, it raises. The Proactor event loop's _call_connection_lost callback then propagates the exception.
Suggested fixes (any of)
- Wrap with
try/except OSError at the daemon-status RPC's connection-close site
- Pin
WindowsSelectorEventLoopPolicy at process start on Windows:
if sys.platform == "win32":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
- Guard the close path with an explicit
is_closed check before calling _winapi.CloseHandle
(1) is the lowest-risk surgical fix. (2) is broader but may have other implications for any subprocess code. (3) is the most correct but requires deeper plumbing.
Current workaround
I'm running a PowerShell-native status check that reads daemon-state.json directly and pings each watcher PID with Get-Process. Source available at https://github.com/Mr-B-1/workspace-control/blob/main/graph/status.ps1 — happy to upstream this as a fallback --no-rpc mode if useful.
Environment
- OS: Windows 11
- Python: 3.11 (Microsoft Store)
- Package:
code-review-graph@latest via uvx
- Daemon was started and watchers verified alive at the time of the status call
Why this matters
The status check is the natural health-probe surface for the daemon, used by scheduled tasks and by humans verifying setup. The current behavior means anything checking daemon status exit code on Windows treats the daemon as broken when it isn't. Working around it requires reading the internal state file directly — fine for one user, not great as a recommendation.
Summary
On Windows,
uvx code-review-graph@latest daemon statusconsistently raisesOSError: [WinError 87] The parameter is incorrecteven when the daemon's watcher PIDs are alive and the daemon is otherwise healthy. The status command is therefore unreliable as a health check on Windows.Repro
uvx code-review-graph@latest daemon start(succeeds; watchers spawn)Get-Process -Id <pid>returns the process for each PID in~/.code-review-graph/daemon-state.jsonuvx code-review-graph@latest daemon statusOSError: [WinError 87] The parameter is incorrectRoot cause hypothesis
This appears to be a known CPython asyncio Proactor handle-close issue family:
_ProactorBasePipeTransport._call_connection_lostleaksOSErrorfromPipeHandle.close()on WindowsPipeHandle.close()is not idempotent at the Win32 level — it calls_winapi.CloseHandleunconditionally, and if the underlying handle has already been closed betweenread_handleandCloseHandle, it raises. The Proactor event loop's_call_connection_lostcallback then propagates the exception.Suggested fixes (any of)
try/except OSErrorat the daemon-status RPC's connection-close siteWindowsSelectorEventLoopPolicyat process start on Windows:is_closedcheck before calling_winapi.CloseHandle(1) is the lowest-risk surgical fix. (2) is broader but may have other implications for any subprocess code. (3) is the most correct but requires deeper plumbing.
Current workaround
I'm running a PowerShell-native status check that reads
daemon-state.jsondirectly and pings each watcher PID withGet-Process. Source available at https://github.com/Mr-B-1/workspace-control/blob/main/graph/status.ps1 — happy to upstream this as a fallback--no-rpcmode if useful.Environment
code-review-graph@latestviauvxWhy this matters
The status check is the natural health-probe surface for the daemon, used by scheduled tasks and by humans verifying setup. The current behavior means anything checking
daemon statusexit code on Windows treats the daemon as broken when it isn't. Working around it requires reading the internal state file directly — fine for one user, not great as a recommendation.