Skip to content

kimi-k3 sessions hang indefinitely with no visible indication #1

Description

@axisrow

Summary

kimi-k3 sessions hang forever with no error and no visible indication in the TUI. The turn's status stays "thinking" indefinitely; only inspecting the process (lsof, log file) shows the stream actually died.

Environment

  • macOS (Darwin 25.5.0, arm64)
  • Local system proxy: HTTPS_PROXY=http://127.0.0.1:8118 (all outbound traffic routed through it)
  • System IPv6 has no working transit to some hosts (confirmed with curl -6), while others resolve fine over IPv6

What's confirmed

  1. The stream genuinely stalls. Log shows stream providerID=opencode modelID=kimi-k3 ... small=false agent=build mode=primary, then nothing — no further token deltas, no error, no completion — for 4+ minutes until the process was killed manually. lsof on the hung process showed established TCP sockets to opencode.ai with txq=0/rxq=0 (nothing being sent or received).

  2. No timeout bounds the connect/send phase. In provider.ts, the fetch call is made with timeout: false (working around Respect timeout passed to fetch oven-sh/bun#16682). chunkTimeout/wrapSSE only guards reading a response body that has already started arriving — it does nothing if the connection never completes or the request body is never fully sent. A stalled connect or a stalled write can block forever.

  3. IPv6 reachability is inconsistent on this network. curl -6 to some hosts fails outright (conn=0.000000s, timeout), to others it succeeds. Whether this is the actual trigger for a given kimi-k3 hang was not conclusively isolated — Bun's own fetch() was observed picking a working IPv4 route on its own in repeated local tests, so an IPv6/Happy-Eyeballs theory alone does not fully explain the hangs.

  4. The TUI gives no signal that anything is wrong. The "thinking" status/spinner is identical whether the model is genuinely processing or the stream has silently died. There is no elapsed-time counter and no token counter shown while a turn is in progress — both are only computed after the turn completes (time.completed), so a hung turn produces no observable difference from a slow one. This is the practical blocker: without any live signal, a stalled stream and a long-running one are indistinguishable from the UI alone, and the only way to tell them apart is external process/network inspection.

Impact

A stalled kimi-k3 turn requires killing the process by hand; there is no way to detect it from within the TUI itself.

Possibly related upstream

None of these are merged upstream yet. This issue is tracking the local investigation and the missing-indication gap specifically (see #2 in this fork for the live-timer fix).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions