Repository navigation
Description
Description
opencode serve can get into a state where the process is still alive and listening on 127.0.0.1:4096, but it no longer responds to any HTTP request, including /global/health.
Restarting the opencode serve process immediately fixes it.
This does not look like a slow route, project bootstrap, MCP, LSP, or plugin initialization issue because /global/health also hangs and receives 0 bytes. The socket/runtime state suggests the listener remains open and registered in epoll, but the thread that normally polls the listener epoll fd stops doing so.
OpenCode version
1.3.17
Command
opencode serve --hostname=127.0.0.1 --port=4096 --log-level=DEBUGSteps to reproduce
I do not have a deterministic reproduction yet. I observed this on a long-running opencode serve process inside a Linux sandbox/container while using the server from a local client.
When wedged, this request connects but times out with 0 bytes:
curl -sv --http1.1 --no-keepalive --max-time 5 http://127.0.0.1:4096/global/healthOutput:
* Trying 127.0.0.1:4096...
* Connected to 127.0.0.1 (127.0.0.1) port 4096
> GET /global/health HTTP/1.1
> Host: 127.0.0.1:4096
> User-Agent: curl/8.5.0
> Accept: */*
>
* Operation timed out after 5002 milliseconds with 0 bytes received
* Closing connection
Expected behavior
/global/health should return quickly:
{"healthy":true,"version":"1.3.17"}Actual behavior
The TCP connection is established, but no HTTP response bytes are returned. The process remains alive and listening, but requests pile up until clients time out. Killing and restarting opencode serve restores normal behavior.
Process state
In one occurrence, the listener process was PID 900:
PID=$(ss -ltnp 'sport = :4096' | grep -o 'pid=[0-9]*' | head -1 | cut -d= -f2)
echo "$PID"
ps -p "$PID" -o pid,ppid,stat,etime,pcpu,pmem,wchan:32,argsOutput:
900
PID PPID STAT ELAPSED %CPU %MEM WCHAN COMMAND
900 7 Sl 40:48 0.1 0.0 futex_wait_queue_me opencode serve --hostname=127.0.0.1 --port=4096 --log-level=DEBUG
After a timed-out /global/health request:
ss -tanpi '( sport = :4096 or dport = :4096 )'Output excerpt:
LISTEN 13 512 127.0.0.1:4096 0.0.0.0:* users:(("opencode",pid=900,fd=16))
cubic cwnd:10 unacked:13
CLOSE-WAIT 91 0 127.0.0.1:4096 127.0.0.1:42694
bytes_received:91 ...
ESTAB 218 0 127.0.0.1:4096 127.0.0.1:59964
bytes_received:218 ...
This suggests opencode is still listening, but not draining the accept backlog or reading request bytes.
strace
I attached strace while issuing a /global/health curl. The trace showed no accept4, read, recvfrom, or write activity for the request. Threads were blocked in futex(...), with one thread blocked in epoll_pwait2(...).
Excerpt from a wedged process:
698 19:16:29.615002 futex(0x3112fa48, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, NULL, FUTEX_BITSET_MATCH_ANY <unfinished ...>
627 19:16:29.615050 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
626 19:16:29.615057 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
625 19:16:29.615063 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
609 19:16:29.615068 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
608 19:16:29.615073 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
607 19:16:29.615079 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
606 19:16:29.615083 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
605 19:16:29.615089 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
604 19:16:29.615094 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
603 19:16:29.615099 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
602 19:16:29.615104 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
601 19:16:29.615109 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
600 19:16:29.615114 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
595 19:16:29.615119 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
469 19:16:29.615125 epoll_pwait2(14, <unfinished ...>
460 19:16:29.615131 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
459 19:16:29.615135 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
458 19:16:29.615141 futex(0x618660c, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
326 19:16:29.615146 futex(0x3112fda8, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, NULL <detached ...>
epoll/fdinfo comparison
In a wedged occurrence, the actual listener fd was 20:
listener=$(ss -ltnp 'sport = :4096' | grep -o 'fd=[0-9]*' | head -1 | cut -d= -f2)
echo "listener fd: $listener"
readlink /proc/$PID/fd/$listener
grep -R "tfd: *$listener" /proc/$PID/fdinfoOutput:
listener fd: 20
socket:[1065114658]
/proc/326/fdinfo/5:tfd: 20 events: 19 data: 28b300a20c0 pos:0 ino:3f7c5c22 sdev:8
So the listener socket was still registered under epoll fd 5.
In a working sandbox, strace during curl /global/health shows a thread polling that listener epoll fd:
epoll_pwait2(5, ...)
In the wedged sandbox, strace no longer shows any thread polling epoll fd 5. Instead, the only visible event-loop wait was:
epoll_pwait2(14, ...)
During that wedged state, /global/health connected but timed out with 0 bytes, ss showed pending listener backlog / unread request bytes / CLOSE-WAIT sockets, and no accept4 / read / write appeared in strace.
This suggests the listener socket remains registered, but the event-loop thread responsible for the listener epoll fd is no longer polling it, or the runtime has otherwise stopped dispatching listener readiness.
Environment
OS: Linux, inside a sandbox/container
OpenCode: 1.3.17
Server command: opencode serve --hostname=127.0.0.1 --port=4096 --log-level=DEBUG
gdb was not available on the machine, so I could not collect native backtraces.
I have observed this in more than one repository/sandbox. Restarting the opencode process fixes the issue immediately.
Additional context
Because /global/health hangs and there is no request/response activity in strace, this appears to be below opencode route handling. It seems more likely to involve the Bun runtime, Node HTTP compatibility, or the @hono/node-server adapter than project/plugin/MCP/LSP code.
Would you prefer this be reported directly to Bun with a reduced reproduction, or is there additional opencode-specific debugging I can collect next time it occurs?
Plugins
No response
OpenCode version
1.3.17
Steps to reproduce
No response
Screenshot and/or share link
No response
Operating System
No response
Terminal
No response
Activity
github-actions commentedon Apr 7, 2026
This issue might be related to previously reported issues. Please check:
/global/healthtimes out with 0 bytes, process alive but unresponsive); different hypothesized root cause but worth reviewing in case the fix there addresses the same underlying runtime behavior.If your issue is a distinct epoll-polling regression not covered by either of those, this report's strace/fdinfo evidence should help distinguish it.
thdxr commentedon Apr 7, 2026
what version were you guys on before?
panta82 commentedon Jun 17, 2026
I've been struggling with this for a while. Excerpts from clanker's slop report:
I observed what looks like the same failure mode on
opencode 1.17.7.Environment
1.17.7Important context
The process had an
LD_PRELOADshim loaded to no-op Bun/WebKit allocatormadvise(..., MADV_DODUMP/MADV_DONTDUMP)calls:This was added because we previously observed a separate Bun allocator issue with an
madvise(..., MADV_DODUMP) = -1 EAGAINloop. During this HTTP wedge, CPU was low and the shim was loaded, so this seems separate from the prior high-CPUmadviseloop.Socket state while wedged
Listener:
There were many server-side sockets stuck in
CLOSE-WAITwith unread request bytes, plus an established nginx upstream connection with unread bytes:The listener backlog kept increasing as probes were made, which suggests connections were arriving but not being drained.
Process/thread state
Process state:
Thread state:
strace while wedged
I attached
straceto the listener PID fromss, then made a localhost request:During the curl probe, there were no observed
accept,accept4,read,recvfrom,sendto, orwritesyscalls servicing the new request.Representative trace excerpts:
So the process was alive, but did not appear to accept or read the request.
Logs
opencode-weblogs showed startup and bootstrap messages, but no useful error around the wedge.Recent startup entries:
No crash, no panic, no route-level error.
github-actions commentedon Aug 17, 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.