You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Windows CLI: WSL2 镜像网络预留范围内的 45278 导致服务启动失败,端口查询无占用记录 #55918
Windows 原生 CLI 启动失败,提示 127.0.0.1:45278 被其他进程占用,但 Windows 和 WSL 均查不到该端口的连接/监听记录。实测该端口位于正在运行的 WSL2 镜像网络的临时端口范围 44620–48715 内。
Starting background server...
Error: Server process exited with code 1
Error: Managed service port 45278 on 127.0.0.1 is already in use by another process.
Configure another port with `opencode service set port <port>` and start the service again.
OpenCode version
2.0.30,Windows 原生 npm 包 @opencode/cli。opencode service get 返回 {},opencode service status 返回 stopped。
Operating System
Windows 11,build 26200.9711;WSL 2.7.3.0,Ubuntu 正在运行。
Thanks for the detailed investigation. I can't recreate the WSL2 mirrored-mode reservation in our Linux sandbox, but I could confirm the OpenCode side:
With no port configured (opencode service get → {}) and the default port blocked, opencode service start fails with Managed service port … is already in use by another process and never tries another port. opencode service status stays stopped. I simulated the blocked port with a plain listener.
The same thing still happens on the latest dev (e25b7ab).
Until this is fixed, opencode service set port <port> with a port outside both your WSL range and the Windows excluded ranges should work around it.
Reproduction script (repro.sh)
#!/usr/bin/env bash# Reproduces #55918's OpenCode-side behaviour on Linux: when the default managed-service# port cannot be bound and no port is configured, `opencode service start` fails with# "already in use by another process" and never falls back to another port.# On Windows (2.0.30+) the default port is 45278 (0xB0DE), which falls inside the WSL2# mirrored-mode ephemeral reservation (e.g. 44620-48715). Here we make the Linux default# port (49374) unbindable to stand in for that reservation.# Usage: ./repro.sh (uses `opencode` from PATH)# OC_DEV=/workspace/repo ./repro.sh (runs the CLI from a source checkout)set -u
# 49374 = default for release channels, 49375 = default for a source checkout ('local' channel)
H=$(mktemp -d)export HOME=$H XDG_CONFIG_HOME=$H/.config XDG_STATE_HOME=$H/.state XDG_DATA_HOME=$H/.data
if [ -n"${OC_DEV:-}" ];then
OC=(bun --conditions=browser --preload="$OC_DEV/packages/tui/node_modules/@opentui/solid/scripts/preload.js""$OC_DEV/packages/cli/src/index.ts")
else
OC=(opencode)
fi"${OC[@]}" --version
python3 -c "import socket,timess=[]for p in (49374,49375): s=socket.socket();s.bind(('127.0.0.1',p));s.listen();ss.append(s)time.sleep(90)"&
BLOCKER=$!
sleep 1
echo"--- service get (no port configured):";"${OC[@]}" service get
echo"--- service start:"if [ -n"${OC_DEV:-}" ];thencd"$OC_DEV/packages/cli";elsecd"$H";fi; timeout 60 "${OC[@]}" service start 2>&1| head -3
echo"--- service status:";"${OC[@]}" service status 2>&1| head -3
kill$BLOCKER2>/dev/null
Independent confirmation from a second machine (Windows 11, Desktop 2.0.32, bundled CLI 2.0.32) — same signature, plus the mechanism and a durable workaround.
Confirming evidence
The port is held by an HNS/WSL dynamic reservation, not by a process. All of these are empty while bind() returns WSAEADDRINUSE (10048):
2026-10-17: the band was free again; only 45278 was blocked, and it was blocked by the (already immunized) port itself
netsh int ipv4 show excludedportrange protocol=tcp does not list the reserved window — only the ports that were manually immunized.
Trigger
networkingMode=mirrored in %USERPROFILE%\.wslconfig with WSL2 running. The mirrored mode makes HNS reserve a large ephemeral window through sockets that never appear in any user-visible socket table. net stop/start winnat does not free it; wsl --shutdown does, but the window is re-drawn on the next start/reboot, so it is not a durable fix.
Durable workaround (verified here)
Reserve the canonical port so it survives the drift — admin shell:
netsh int ipv4 add excludedportrange protocol=tcp startport=45278 numberofports=1
After this, 45278 stays bindable even when WSL re-draws its window, and the managed service starts normally on it. (Observed working across a WSL restart.)
WSL-side lever worth documenting too: ignoredPorts (experimental section of .wslconfig) controls which ports Linux may bind even when Windows uses them.
Suggestions
Error text: the current message ("already in use by another process") sends users hunting for a process that does not exist. Distinguishing "a process holds this port" from "the OS refuses this port" (e.g. by counting how many neighbouring ports also fail to bind) would point at the real cause in one step.
Default port: on Windows with WSL2 present, either pick a default outside the Linux ephemeral range or probe and report before failing.
Docs: mention the excludedportrange immunization and the mirrored-mode interaction in the service/port troubleshooting page.
Related: #55907 (same class, desktop), #52234 (hardcoded default port without fallback), #54267 (different cause — a previous service not exiting). A comparable case in another Electron app: httptoolkit/httptoolkit#901.
Confirmed on Windows Desktop 2.0.32 with its bundled CLI 2.0.32 after an in-app update. The desktop failed with Desktop IPC handler failed and the nested error Managed service port 45278 on 127.0.0.1 is already in use by another process.
Environment: Windows 11 build 26200.8737; WSL 3.0.3.0, kernel 6.18.54.1-microsoft-standard-WSL2; Ubuntu running with networkingMode=mirrored.
wsl -d Ubuntu --exec cat /proc/sys/net/ipv4/ip_local_port_range returns 44620 48715. Windows TCP tables and WSL ss show no socket on 45278. Neither the IPv4 nor IPv6 excluded-port list includes this range.
Independent Windows .NET socket bind tests, closing each socket immediately:
Port
Result
44619
Success
44620, 44621
WSAEADDRINUSE / 10048
45278
WSAEADDRINUSE / 10048
48714, 48715
WSAEADDRINUSE / 10048
48717, 48718, 49374
Success
45278 also fails on IPv4 wildcard, IPv6 loopback, and a local NIC address. This matches the mirrored-mode reservation described by Microsoft in microsoft/WSL#12228 and microsoft/WSL#40169.
Verified recovery: using the desktop-bundled CLI, service set port 48716 followed by service start succeeds. Restarting Desktop restores the existing session; its main log reports v2 CLI background service ready, version 2.0.32, URL http://127.0.0.1:48716. The model configuration's SHA-256 is unchanged. No system networking settings were changed.
I did not stop/restart WSL or reboot Windows as a control, so this confirms recovery for the current reservation, not durability across WSL restarts.
This extends the report to the desktop's current bundled service. Please consider a bind-tested fallback for an unconfigured/default service port, preserving service discovery and explicit user port settings, plus an error that includes OS/WSL reservation as a possible cause. Moving the default below Windows' dynamic range alone (#55547) does not avoid the WSL mirrored range.
Can reproduce on OpenCode v2.0.32 (Windows 11 build 26300, PowerShell 7.6.7). Running plugin update fails on 45279 and 45280 despite no active listener in Get-NetTCPConnection and neither port being listed in netsh excludedportrange. Workaround: 'opencode service set port 12580' resolved the issue immediately.
Additional confirmation on Desktop 2.0.32 (bundled CLI 2.0.32, Windows 11 10.0.26300), including the exact port-derivation and a workaround that survives the reserved window moving.
Port derivation (extracted from the 2.0.32 opencode-cli.exe bundle):
functionA(e){// default per channelif(e==="latest"||e==="dev"||e==="beta"||e==="next")return49374;if(e==="local")return49375;return1e4+parseInt(hash(e).slice(0,8),16)%50000;}functionDDe(e,r="win32"){// win32 remapconstl=A(e);if(r==="win32"&&l>=49152)return45056|(l&4095);returnl;}
45056 | (49374 & 4095) = 45278. So this is not a random collision: every Windows default is parked in 45056–49151, while WSL mirrored mode reserves the guest ephemeral range (44620–48715 on this machine, exactly /proc/sys/net/ipv4/ip_local_port_range). Overlap: 45056–48715 = 3660 of 4096 ports (89.4%). Roughly 9 out of 10 mappings are unusable whenever WSL2 mirrored networking is running.
netsh int ipv4/ipv6 show excludedportrange → only 5357 and 50000–50059; 45278 is not listed
bind tests: 45278 → 10048 (no SO_REUSEADDR) / 10013 (with SO_REUSEADDR); the whole 44620–48715 block behaves identically; 30000, 40000, 48716, 49374 bind fine
a sweep of 44000–49200 yields a blocked window exactly 44620–48715, matching the distro's ephemeral range (WSL 2.6.3.0, networkingMode=mirrored)
WSL started at 08:51; Desktop failed at 08:54. On 10-17 the same port failed immediately after the 2.0.28→2.0.32 update (reason: 'version-mismatch', previousVersion: '2.0.28'), then succeeded at 21:50 when the reservation was not active.
Workaround robust to the window moving: pick a port below 32768 (outside both the WSL range and the Windows dynamic range):
opencode-cli.exe service set port 31415opencode-cli.exe service restart
Verified on Desktop 2.0.32: service.json → {"port":31415}, service ready at http://127.0.0.1:31415. Ports near the band edges (44619, 48716) work today but are only one port away from the reservation and will break when the window shifts.
Suggestion: since 89.4% of the current Windows remap band is unusable under WSL mirrored mode, either remap below 32768, or bind-test the selected default and fall back to a registered ephemeral port. Also, "already in use by another process" should distinguish WSAEACCES/reserved ranges from a real listener.
Activity
opencode-agent commentedon Oct 16, 2026
Thanks for the detailed investigation. I can't recreate the WSL2 mirrored-mode reservation in our Linux sandbox, but I could confirm the OpenCode side:
0xB000 | (port & 0xFFF), which gives 45278 (from fix(cli): default the Windows service to port 45278 #55547). That's inside your WSL mirrored ephemeral range (44620–48715).opencode service get→{}) and the default port blocked,opencode service startfails withManaged service port … is already in use by another processand never tries another port.opencode service statusstaysstopped. I simulated the blocked port with a plain listener.dev(e25b7ab).The script below reproduces it on Linux.
Related:
Until this is fixed,
opencode service set port <port>with a port outside both your WSL range and the Windows excluded ranges should work around it.Reproduction script (repro.sh)
Run it:
bash repro.shMr-YW commentedon Oct 16, 2026
因为这个桌面端打不开,转用DeepSeek Hermes了,意外的是还挺好用的
deadczarvc commentedon Oct 17, 2026
Independent confirmation from a second machine (Windows 11, Desktop 2.0.32, bundled CLI 2.0.32) — same signature, plus the mechanism and a durable workaround.
Confirming evidence
The port is held by an HNS/WSL dynamic reservation, not by a process. All of these are empty while
bind()returnsWSAEADDRINUSE (10048):netstat -ano | findstr 45278— emptyGet-NetTCPConnection -LocalPort 45278(including-State Bound) — emptyGetExtendedTcpTable(..., TCP_TABLE_OWNER_PID_ALL)probe (C/WinAPI, no shell tooling) — 0 rowsBinding with
SO_REUSEADDRfails with10013 (WSAEACCES)— the documented signature of a reserved/excluded range.Bisection distinguishes the two cases. Probing neighbours shows a wide block (~4,000 ports), not a single busy port:
On earlier runs the whole band
41900–45989failed. So the reserved window moves:41890–45999(afterwsl --shutdown) →37795–4189045278was blocked, and it was blocked by the (already immunized) port itselfnetsh int ipv4 show excludedportrange protocol=tcpdoes not list the reserved window — only the ports that were manually immunized.Trigger
networkingMode=mirroredin%USERPROFILE%\.wslconfigwith WSL2 running. The mirrored mode makes HNS reserve a large ephemeral window through sockets that never appear in any user-visible socket table.net stop/start winnatdoes not free it;wsl --shutdowndoes, but the window is re-drawn on the next start/reboot, so it is not a durable fix.Durable workaround (verified here)
Reserve the canonical port so it survives the drift — admin shell:
After this,
45278stays bindable even when WSL re-draws its window, and the managed service starts normally on it. (Observed working across a WSL restart.)WSL-side lever worth documenting too:
ignoredPorts(experimental section of.wslconfig) controls which ports Linux may bind even when Windows uses them.Suggestions
excludedportrangeimmunization and the mirrored-mode interaction in the service/port troubleshooting page.Related: #55907 (same class, desktop), #52234 (hardcoded default port without fallback), #54267 (different cause — a previous service not exiting). A comparable case in another Electron app: httptoolkit/httptoolkit#901.
BigBear0099 commentedon Oct 19, 2026
Confirmed on Windows Desktop 2.0.32 with its bundled CLI 2.0.32 after an in-app update. The desktop failed with
Desktop IPC handler failedand the nested errorManaged service port 45278 on 127.0.0.1 is already in use by another process.Environment: Windows 11 build 26200.8737; WSL 3.0.3.0, kernel 6.18.54.1-microsoft-standard-WSL2; Ubuntu running with
networkingMode=mirrored.wsl -d Ubuntu --exec cat /proc/sys/net/ipv4/ip_local_port_rangereturns 44620 48715. Windows TCP tables and WSLssshow no socket on 45278. Neither the IPv4 nor IPv6 excluded-port list includes this range.Independent Windows .NET socket bind tests, closing each socket immediately:
45278 also fails on IPv4 wildcard, IPv6 loopback, and a local NIC address. This matches the mirrored-mode reservation described by Microsoft in microsoft/WSL#12228 and microsoft/WSL#40169.
Verified recovery: using the desktop-bundled CLI,
service set port 48716followed byservice startsucceeds. Restarting Desktop restores the existing session; its main log reportsv2 CLI background service ready, version 2.0.32, URLhttp://127.0.0.1:48716. The model configuration's SHA-256 is unchanged. No system networking settings were changed.I did not stop/restart WSL or reboot Windows as a control, so this confirms recovery for the current reservation, not durability across WSL restarts.
This extends the report to the desktop's current bundled service. Please consider a bind-tested fallback for an unconfigured/default service port, preserving service discovery and explicit user port settings, plus an error that includes OS/WSL reservation as a possible cause. Moving the default below Windows' dynamic range alone (#55547) does not avoid the WSL mirrored range.
SHJordan commentedon Oct 19, 2026
Can reproduce on OpenCode v2.0.32 (Windows 11 build 26300, PowerShell 7.6.7). Running plugin update fails on 45279 and 45280 despite no active listener in Get-NetTCPConnection and neither port being listed in netsh excludedportrange. Workaround: 'opencode service set port 12580' resolved the issue immediately.
jiem88 commentedon Oct 20, 2026
Additional confirmation on Desktop 2.0.32 (bundled CLI 2.0.32, Windows 11 10.0.26300), including the exact port-derivation and a workaround that survives the reserved window moving.
Port derivation (extracted from the 2.0.32
opencode-cli.exebundle):45056 | (49374 & 4095)= 45278. So this is not a random collision: every Windows default is parked in 45056–49151, while WSL mirrored mode reserves the guest ephemeral range (44620–48715 on this machine, exactly/proc/sys/net/ipv4/ip_local_port_range). Overlap: 45056–48715 = 3660 of 4096 ports (89.4%). Roughly 9 out of 10 mappings are unusable whenever WSL2 mirrored networking is running.Evidence (same signature as reported above):
netstat -ano | findstr :45278→ empty;Get-NetTCPConnection -LocalPort 45278→ 0 rowsnetsh int ipv4/ipv6 show excludedportrange→ only 5357 and 50000–50059; 45278 is not listed45278→10048(noSO_REUSEADDR) /10013(withSO_REUSEADDR); the whole44620–48715block behaves identically;30000,40000,48716,49374bind fine44620–48715, matching the distro's ephemeral range (WSL 2.6.3.0,networkingMode=mirrored)reason: 'version-mismatch', previousVersion: '2.0.28'), then succeeded at 21:50 when the reservation was not active.Workaround robust to the window moving: pick a port below 32768 (outside both the WSL range and the Windows dynamic range):
Verified on Desktop 2.0.32:
service.json→{"port":31415}, service ready athttp://127.0.0.1:31415. Ports near the band edges (44619, 48716) work today but are only one port away from the reservation and will break when the window shifts.Suggestion: since 89.4% of the current Windows remap band is unusable under WSL mirrored mode, either remap below 32768, or bind-test the selected default and fall back to a registered ephemeral port. Also, "already in use by another process" should distinguish
WSAEACCES/reserved ranges from a real listener.