Skip to content

Commit 1dce282

Browse files
Fix panic on send to closed event channel in Go SDK
Protect dispatchEvent with a recover guard so that a notification arriving after Disconnect does not crash the process. Also wrap the channel close in sync.Once so Disconnect is safe to call more than once. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent e320690 commit 1dce282

1 file changed

Lines changed: 8 additions & 2 deletions

File tree

go/session.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ type Session struct {
6767

6868
// eventCh serializes user event handler dispatch. dispatchEvent enqueues;
6969
// a single goroutine (processEvents) dequeues and invokes handlers in FIFO order.
70-
eventCh chan SessionEvent
70+
eventCh chan SessionEvent
71+
closeOnce sync.Once // guards eventCh close so Disconnect is safe to call more than once
7172

7273
// RPC provides typed session-scoped RPC methods.
7374
RPC *rpc.SessionRpc
@@ -451,6 +452,11 @@ func (s *Session) handleHooksInvoke(hookType string, rawInput json.RawMessage) (
451452
// serial, FIFO dispatch without blocking the read loop.
452453
func (s *Session) dispatchEvent(event SessionEvent) {
453454
go s.handleBroadcastEvent(event)
455+
456+
// Use a recover guard because eventCh may be closed by Disconnect.
457+
// In Go, sending on a closed channel panics and there is no
458+
// non-panicking send primitive.
459+
defer func() { recover() }()
454460
s.eventCh <- event
455461
}
456462

@@ -657,7 +663,7 @@ func (s *Session) Disconnect() error {
657663
return fmt.Errorf("failed to disconnect session: %w", err)
658664
}
659665

660-
close(s.eventCh)
666+
s.closeOnce.Do(func() { close(s.eventCh) })
661667

662668
// Clear handlers
663669
s.handlerMutex.Lock()

0 commit comments

Comments
 (0)