From cb13f6523cc6245cedcffdbcbae1b7bb5ffcfd40 Mon Sep 17 00:00:00 2001 From: Ollie Agent Date: Sat, 1 Aug 2026 20:32:18 +0200 Subject: [PATCH] fs/session: fix deadlock in agent/new via setAgentLogLocked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SetAgentLog acquires sess.mu, but CreateAgent in create.go already holds sess.mu when calling it — causing a deadlock on agent/new writes. Split into SetAgentLog (locks) and setAgentLogLocked (no lock) so callers that already hold the lock can use the locked variant directly. --- fs/session/create.go | 4 ++-- fs/session/types.go | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/session/create.go b/fs/session/create.go index 8ebe513..31776c6 100644 --- a/fs/session/create.go +++ b/fs/session/create.go @@ -264,12 +264,12 @@ func CreateAgent(rs *rootState, sessName string, args []string) error { ReadPlanStep: func() string { return "" }, - }) +}) sess.mu.Lock() sess.Core = core sess.uname = uname - sess.SetAgentLog(uname, al) + sess.setAgentLogLocked(uname, al) sess.proc = proc sess.mu.Unlock() diff --git a/fs/session/types.go b/fs/session/types.go index f2ee86d..ebdc040 100644 --- a/fs/session/types.go +++ b/fs/session/types.go @@ -79,6 +79,11 @@ func (sess *Session) AgentLog() *AgentLog { func (sess *Session) SetAgentLog(agentID string, al *AgentLog) { sess.mu.Lock() defer sess.mu.Unlock() + sess.setAgentLogLocked(agentID, al) +} + +// setAgentLogLocked is like SetAgentLog but assumes sess.mu is already held. +func (sess *Session) setAgentLogLocked(agentID string, al *AgentLog) { if sess.AgentLogs == nil { sess.AgentLogs = make(map[string]*AgentLog) }