From 2420fc7b76f52ee67c000b0a98248c3e50b88c2d Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 8 Jul 2026 18:24:18 +0200 Subject: [PATCH] Lock the status list when reading it GetStatusString and HasStatus read the statuses slice without holding the mutex that addStatus and removeStatus take when they mutate it. The readers run on the spinner-render worker (which polls GetStatusString every frame) while removeStatus fires from the waiting-status and toast-expiry goroutines, so the unguarded reads race the concurrent writes. Take the mutex in the readers too. Co-Authored-By: Claude Opus 4.8 (1M context) --- pkg/gui/status/status_manager.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/gui/status/status_manager.go b/pkg/gui/status/status_manager.go index 2f822c1ee..414568a69 100644 --- a/pkg/gui/status/status_manager.go +++ b/pkg/gui/status/status_manager.go @@ -70,6 +70,9 @@ func (self *StatusManager) AddToastStatus(message string, kind types.ToastKind) } func (self *StatusManager) GetStatusString(userConfig *config.UserConfig) (string, gocui.Attribute) { + self.mutex.Lock() + defer self.mutex.Unlock() + if len(self.statuses) == 0 { return "", gocui.ColorDefault } @@ -81,6 +84,9 @@ func (self *StatusManager) GetStatusString(userConfig *config.UserConfig) (strin } func (self *StatusManager) HasStatus() bool { + self.mutex.Lock() + defer self.mutex.Unlock() + return len(self.statuses) > 0 }