Observed 2026-09-03 by the usbif session on the bench, mid hardware bring-up. Every mpftp subcommand failed, first as
Expecting value: line 1 column 1 (char 0)
with the hint that the serial port "may be dead or busy" (cli/src/mpftp/cli.py:543), and on a closer look as
sidecar exited early: <3>WSL (387453 - ) ERROR: UtilAcceptVsock:280: accept4 failed 110
That is not the board and not the port: the CH343 showed Status OK on the Windows side, mpftp ports had enumerated COM49 earlier, and the same board was driven fine over pyserial from the Windows interpreter. It is the WSL interop transport that SidecarClient (cli.py:370-399) relies on to launch python.exe: a long-lived shell holding a WSL_INTEROP socket whose owner is gone makes every .exe launch time out on accept (errno 110). From a fresh session on the same machine at the same moment, mpftp status and mpftp ports both worked — so the failure is per-shell, and the "dead or busy serial port" hint sends the user to the wrong place.
Cheap fix (do this): when the sidecar dies before ready and its stderr contains UtilAcceptVsock / accept4 failed, say so:
the Windows-python sidecar could not be launched over WSL interop (stale WSL_INTEROP socket). Try export WSL_INTEROP=/run/WSL/2_interop (init's socket, always live) and re-run; wsl --shutdown is the heavy alternative.
_wslenv_forwarded_env (cli.py:324) already builds the sidecar's environment on WSL and is the natural place to substitute a live socket automatically when $WSL_INTEROP no longer exists (os.path.exists on it is a one-line check).
Bigger item (consider): a direct pyserial transport for when interop is unavailable at all. The usbif session's workaround was a ~40-line raw-REPL runner over pyserial (interrupt, \x01 raw REPL, send, \x04, read to the second \x04, \x02 out — raw mode, because the friendly REPL echoes and re-wraps). That is the shape of the fallback; whether it belongs in mpftp or stays a bench script is the question this issue asks. Two WSL-interop failures on one bench in one day is the argument for it.
Observed 2026-09-03 by the usbif session on the bench, mid hardware bring-up. Every
mpftpsubcommand failed, first aswith the hint that the serial port "may be dead or busy" (
cli/src/mpftp/cli.py:543), and on a closer look asThat is not the board and not the port: the CH343 showed Status OK on the Windows side,
mpftp portshad enumerated COM49 earlier, and the same board was driven fine over pyserial from the Windows interpreter. It is the WSL interop transport thatSidecarClient(cli.py:370-399) relies on to launchpython.exe: a long-lived shell holding aWSL_INTEROPsocket whose owner is gone makes every.exelaunch time out on accept (errno 110). From a fresh session on the same machine at the same moment,mpftp statusandmpftp portsboth worked — so the failure is per-shell, and the "dead or busy serial port" hint sends the user to the wrong place.Cheap fix (do this): when the sidecar dies before
readyand its stderr containsUtilAcceptVsock/accept4 failed, say so:_wslenv_forwarded_env(cli.py:324) already builds the sidecar's environment on WSL and is the natural place to substitute a live socket automatically when$WSL_INTEROPno longer exists (os.path.existson it is a one-line check).Bigger item (consider): a direct pyserial transport for when interop is unavailable at all. The usbif session's workaround was a ~40-line raw-REPL runner over pyserial (interrupt,
\x01raw REPL, send,\x04, read to the second\x04,\x02out — raw mode, because the friendly REPL echoes and re-wraps). That is the shape of the fallback; whether it belongs in mpftp or stays a bench script is the question this issue asks. Two WSL-interop failures on one bench in one day is the argument for it.