anomalyco / anomalyco/opencode
SSE /global/event and /event deliver only server.connected + heartbeats — no message events reach any subscriber (1.18.25)
@neriousy is already working on this.
Since Sep 2, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Description
On OpenCode 1.18.25 (managed by OpenChamber 1.22.0), the SSE event streams (/event and /global/event) accept connections and deliver server.connected + server.heartbeat, but no message events (message.part.updated, message.updated, session.status, session.idle, etc.) are ever delivered to any SSE subscriber — including direct localhost connections with no proxy in the path.
Sessions run normally: tokens stream, the LLM responds, session.messages() returns the completed content. But live event delivery to SSE clients is completely broken. A manual page refresh shows the updates (the server has the data), but real-time updates never arrive.
This reproduces on every client — desktop browser on localhost:5555 (no proxy), desktop browser over Tailscale Serve HTTPS, and mobile browser over Tailscale. It is not proxy-specific or mobile-specific.
Environment
- OS: Arch Linux (kernel 6.x, x86_64)
- OpenCode: 1.18.25 (binary at
~/.opencode/bin/opencode, dated Aug 28) - OpenChamber: 1.22.0 (manages the OpenCode instance, port 5555)
- Runtime: Bun (bundled in the OpenCode binary)
- Provider: ollama-cloud (glm-5.2) — also reproduced with other providers
- No reverse proxy on the localhost path (OpenChamber binds
0.0.0.0:5555directly) - Tailscale Serve is configured but the bug reproduces without it
Steps to reproduce
- Start OpenCode via OpenChamber (or
opencode servedirectly). - Connect to the SSE stream:
curl -sN -u "opencode:<password>" \ -H "Accept: text/event-stream" \ http://127.0.0.1:<port>/global/event - In a separate terminal, send a prompt to a session (or use an active session in OpenChamber).
- Observe the SSE output: only
server.connectedandserver.heartbeatarrive. Nomessage.*,session.status,session.idle, or any other content events.
Expected behavior
The SSE stream delivers message.part.delta, message.part.updated, message.updated, session.status, session.idle, etc. as the session processes — as it did in earlier versions.
Actual behavior
Only server.connected and server.heartbeat are delivered. No message events. The session runs to completion server-side, but no subscriber sees it live.
Evidence
1. SSE stream output (OpenCode /global/event directly, with auth, while session active)
data: {"payload":{"id":"evt_...","type":"server.connected","properties":{}}}
data: {"payload":{"id":"evt_...","type":"server.heartbeat","properties":{}}}
data: {"payload":{"id":"evt_...","type":"server.heartbeat","properties":{}}}
25-second capture during an actively streaming session. Only heartbeats.
2. OpenCode log shows ZERO bus publish lines
In 357,019 lines of ~/.local/share/opencode/log/opencode.log, there are zero service=bus type=... publishing lines. The session is actively processing (process, stream, loop, llm runtime selected all appear), but events are not being published to the bus — or at least not logged as such, and not delivered to SSE subscribers.
For comparison, the older reports (#26866, #27966) showed service=bus type=message.part.updated publishing in the server log even when SSE delivery was broken. Here, those lines are absent entirely.
3. OpenChamber's SSE fan-in confirms the same
OpenChamber proxies from OpenCode's /global/event to its own /api/global/event. Testing OpenChamber's endpoint directly shows the same symptom — only server.connected + heartbeats — confirming the break is upstream in OpenCode, not in OpenChamber.
4. Manual refresh works
Reloading the page in any browser shows the completed session content. The server has the data; only live event delivery is broken.
5. Not proxy-specific
Reproduces on:
- desktop browser, no proxy
- desktop browser, raw Tailscale IP, no proxy
- desktop + mobile, Tailscale Serve HTTPS proxy
All three show the same symptom.
Related issues
This matches a known class of SSE event-delivery regression:
- #39729 — "Web UI: a tab's /global/event stream silently stops delivering when several tabs are connected" — identifies the GlobalBus listener leak as the root cause. The
acquireReleasefinalizer never runs on disconnect, so listeners accumulate and silently kill event delivery. Reproduced on 1.18.5. - #28492 — the underlying GlobalBus listener leak. Shows
16 connections → 16× "global event connected", 0× "global event disconnected". - #31922 — the fix for #39729/#28492 (+130/-17 lines, touches
global.ts,event.ts). Written but never reviewed — closed by the automated PR-cleanup bot for staleness. - #44782 — "opencode run hangs after 'event connected'" on 1.18.21. Same version line, same "event connected then nothing" symptom. Assigned to @jlongster, still open.
- #41986 — "[global-sdk] event stream failed race condition" on 1.18.16+. UI hangs indefinitely after
server ready. - #27966 — the original SyncEvent delivery regression (1.14.42+), supposedly fixed in 1.15.5 via #27825, #28051, #27959, #28187. The symptom matches exactly.
Notes
- 1.18.26 (latest) does not fix this — its release notes only mention Claude 5 thinking blocks, Bedrock GPT-5.6, and tool call timing. Nothing about SSE/GlobalBus.
- The fix (PR #31922) exists but was never merged. Re-landing it may resolve this.
- This breaks all real-time usage of OpenCode through any SSE client (OpenChamber, custom integrations, etc.).
Plugins
No response
OpenCode version
1.18.25
Steps to reproduce
No response
Screenshot and/or share link
No response
Operating System
No response
Terminal
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.