Repository navigation
Description
Description
When opencode serve exits or crashes, the server port (e.g. 4096) is not released. A self-loopback TCP connection (127.0.0.1:54420 ↔ 127.0.0.1:4096, both endpoints owned by the now-dead server PID) remains in ESTABLISHED state, keeping the LISTENING socket locked. On Windows, this port cannot be reclaimed by a new opencode serve --port 4096 invocation — it fails with ServeError: Unexpected error.
The dead process (PID 19152) no longer exists in the process table, but the Windows kernel TCP stack keeps the socket open because the self-loopback ESTABLISHED connection never receives a FIN/RST from either end. All other client connections are stuck in CLOSE_WAIT, also waiting on this zombie self-connection.
This is related to #22198 (SSE connections stuck in CLOSE_WAIT) but is a distinct issue: the root cause here is that opencode serve does not perform graceful socket shutdown on exit, leaving a self-loopback connection that locks the listening port indefinitely on Windows.
Evidence
- ServeError on restart:
opencode serve --port 4096→Error: Unexpected error / ServeError - Dead PID still holds LISTENING:
netstat -anoshowsLISTENING 127.0.0.1:4096 PID 19152, buttasklist /fi "pid eq 19152"→ "No tasks running which match the specified criteria" - Self-loopback ESTABLISHED:
netstat -anoshows127.0.0.1:54420 ↔ 127.0.0.1:4096 ESTABLISHED PID 19152on both sides — a connection from the server to itself that was never closed - 54+ CLOSE_WAIT connections: All other connections to port 4096 are in CLOSE_WAIT, waiting on the zombie self-connection
- Port never releases: Killed all OpenCode Desktop processes, killed all Edge browser processes, waited several minutes — port 4096 still held by dead PID 19152. Only a full OS reboot clears it.
Steps to reproduce
- Start
opencode serve --port 4096(WSL2 or Windows) - Open OpenCode Desktop and connect it to the server (this creates SSE connections including self-loopback)
- Kill the
opencode serveprocess (e.g. close the terminal, or the process crashes) - Attempt to restart:
opencode serve --port 4096→ServeError: Unexpected error - Verify with
netstat -ano | findstr 4096: LISTENING socket still held by dead PID, with a self-loopback ESTABLISHED connection
Expected behavior
opencode serve should perform graceful shutdown on exit:
- Close all SSE streams and send FIN to connected clients
- Close the self-loopback connection (if any)
- Close the LISTENING socket
- The port should be immediately available for a new instance
Suggested fix
- Register a process exit handler (
process.on('exit'),process.on('SIGTERM'),process.on('SIGINT')) that callsserver.close()and closes all active connections - On Windows, also call
server.removeAllListeners()and explicitly destroy sockets that are in CLOSE_WAIT - Consider adding a TCP keepalive/idle timeout on SSE connections so zombie connections eventually self-close even if the server process dies ungracefully
Plugins
oh-my-openagent
OpenCode version
OpenCode Desktop v1.17.8 / opencode-web (latest)
Operating System
Windows 11 (WSL2, Ubuntu 24.04)
Terminal
Windows Terminal / PowerShell
Activity
HaonanQiu commentedon Jul 8, 2026
same problem
arashi-dev commentedon Jul 22, 2026
Any updates? I still have this problem and looks like there is something going on here aictrl-dev/cli#94
WhiteGiverMa commentedon Jul 22, 2026
now I use systemd to manage opencode service in WSL so I didnt meet this for a long time.
arashi-dev commentedon Jul 23, 2026
@WhiteGiverMa That's sounds interesting, can you share your systemd config please?
WhiteGiverMa commentedon Jul 23, 2026
@arashi-dev Sure. This is the user-level systemd unit I use in WSL (
~/.config/systemd/user/opencode-serve.service):I enable and start it with:
systemctl --user daemon-reload systemctl --user enable --now opencode-serve.serviceI also use local drop-ins for authentication and proxy settings. For example, the authentication drop-in should look like this, with your own password:
Using systemd as the supervisor has worked around the issue for me: when the process exits or fails, systemd owns the process lifecycle and restarts the service, so I have not encountered the stuck-port problem for a long time.
This is only a workaround, not a fix in OpenCode itself. Running
opencode weboropencode servedirectly, outside systemd, may still reproduce the same issue.arashi-dev commentedon Jul 23, 2026
@WhiteGiverMa Thank you very much!
github-actions commentedon Sep 22, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.