Skip to content

Fix idle-timer race and add sidecar exit diagnostics#458

Merged
danshapiro merged 2 commits into
mainfrom
fix/opencode-sidecar-diagnostics
Jun 21, 2026
Merged

Fix idle-timer race and add sidecar exit diagnostics#458
danshapiro merged 2 commits into
mainfrom
fix/opencode-sidecar-diagnostics

Conversation

@danshapiro

Copy link
Copy Markdown
Owner

Summary

Fixes two issues discovered during investigation of the freshopencode /new hang:

Idle-timer race (kata njfz)

The idle-shutdown timer deleted the runningByCwd entry before killing the sidecar process. When the child exited and the close handler fired, its guard (runningByCwd.get(cwdKey)) returned undefined, so forgetSessionsForCwd was never called. This leaked session emitters and left pending onceIdle promises hanging for the full 10-minute timeout.

Fix: Call forgetSessionsForCwd before deleting the runningByCwd entry in the idle timer callback. This emits 'lost' events on session emitters, causing pending onceIdle promises to reject promptly with OpencodeServeLostError.

Sidecar exit diagnostics (kata 0ryp)

Every sidecar exit across 15+ log entries showed code: null (killed by signal), but the close handler only logged code, not signal, making it impossible to distinguish SIGTERM (idle timer/external), SIGKILL (OOM), or SIGSEGV (crash).

Fixes:

  • Log signal alongside code in the close handler
  • Log a distinctive info message before idle-timer kill (distinguishes idle-timer kills from crash kills)
  • Capture sidecar stderr at debug level instead of silently draining (captures Go panic/segfault output)

onceIdle 'lost' event fix

Includes the onceIdle 'lost' event fix from debug/freshopencode-new-hang (cherry-picked as base). This branch supersedes that branch.

Test plan

  • 5 new unit tests (2 for idle-timer race, 3 for diagnostics)
  • All 44 serve-manager tests pass
  • All 267 fresh-agent tests pass
  • Full coordinated suite green (default + server configs)
  • TypeScript typecheck clean

codex added 2 commits June 21, 2026 14:48
When the opencode serve sidecar process dies during a turn (crash, OOM,
or idle-shutdown race), onceIdle previously held a dangling promise for
the full 10-minute turnTimeoutMs. This caused freshopencode tabs to
hang indefinitely — the client stayed 'running' and queued all
subsequent messages.

Now forgetSessionsForCwd emits a 'lost' event on each session emitter
before deleting it. onceIdle listens for 'lost' and rejects immediately
with OpencodeServeLostError. The adapter's materializeOrSend catch
block already emits idle status and re-throws, so the client receives
both the idle status (unblocking the UI) and the error message.
Fix idle-timer race (kata njfz): the idle-shutdown timer deleted the
runningByCwd entry before killing the sidecar, so the close handler's
guard failed and forgetSessionsForCwd was never called — leaking session
emitters and leaving pending onceIdle promises hanging. Now calls
forgetSessionsForCwd before deletion, emitting 'lost' events so onceIdle
rejects promptly.

Add sidecar exit diagnostics (kata 0ryp):
- Log signal (not just code) in close handler to distinguish SIGTERM/
  SIGKILL/SIGSEGV
- Log a distinctive info message before idle-timer kill
- Capture sidecar stderr at debug level instead of draining silently

Includes onceIdle 'lost' event fix from debug/freshopencode-new-hang
(cherry-picked as base — this branch supersedes it).
@danshapiro danshapiro merged commit 4b06844 into main Jun 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants