From 2ebc076b9e2c7977b2bcb1a229e7844e5619e1b3 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Thu, 2 Apr 2026 14:18:26 +0100 Subject: [PATCH] fix: make 'chat has no workspace agent' error actually helpful (#23971) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Change `errChatHasNoWorkspaceAgent` message from cryptic `"chat has no workspace agent"` to actionable `"workspace has no running agent: the workspace may be stopped. Use the start_workspace tool to start it, or create_workspace to create a new one"` - Update test assertions to match the new message substring > 🤖 Written by a Coder Agent. Reviewed by a human. --- coderd/x/chatd/chatd.go | 6 +++--- coderd/x/chatd/chatd_test.go | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/coderd/x/chatd/chatd.go b/coderd/x/chatd/chatd.go index 3765038197..f7b8b297c6 100644 --- a/coderd/x/chatd/chatd.go +++ b/coderd/x/chatd/chatd.go @@ -93,7 +93,7 @@ const ( defaultSubagentInstruction = "You are running as a delegated sub-agent chat. Complete the delegated task and provide clear, concise assistant responses for the parent agent." ) -var errChatHasNoWorkspaceAgent = xerrors.New("chat has no workspace agent") +var errChatHasNoWorkspaceAgent = xerrors.New("workspace has no running agent: the workspace is likely stopped. Use the start_workspace tool to start it") // Server handles background processing of pending chats. type Server struct { @@ -344,7 +344,7 @@ func (c *turnWorkspaceContext) loadWorkspaceAgentLocked( } if !chatSnapshot.WorkspaceID.Valid { - return chatSnapshot, database.WorkspaceAgent{}, xerrors.New("chat has no workspace") + return chatSnapshot, database.WorkspaceAgent{}, xerrors.New("no workspace is associated with this chat. Use the create_workspace tool to create one") } if chatSnapshot.AgentID.Valid { @@ -4441,7 +4441,7 @@ func (p *Server) runChat( workspaceCtx.chatStateMu.Unlock() if !chatSnapshot.WorkspaceID.Valid { - return uuid.Nil, xerrors.New("chat has no workspace") + return uuid.Nil, xerrors.New("no workspace is associated with this chat. Use the create_workspace tool to create one") } ws, err := p.db.GetWorkspaceByID(ctx, chatSnapshot.WorkspaceID.UUID) diff --git a/coderd/x/chatd/chatd_test.go b/coderd/x/chatd/chatd_test.go index 7e634bdf1b..69a4d4964c 100644 --- a/coderd/x/chatd/chatd_test.go +++ b/coderd/x/chatd/chatd_test.go @@ -2486,7 +2486,7 @@ func TestStoppedWorkspaceWithPersistedAgentBindingDoesNotBlockChat(t *testing.T) if message.Role != "tool" { continue } - if strings.Contains(message.Content, "chat has no workspace agent") { + if strings.Contains(message.Content, "workspace has no running agent") { foundUnavailableToolResult = true break } @@ -2499,8 +2499,8 @@ func TestStoppedWorkspaceWithPersistedAgentBindingDoesNotBlockChat(t *testing.T) } errMsg, _ := toolResult["error"].(string) outputMsg, _ := toolResult["output"].(string) - if strings.Contains(errMsg, "chat has no workspace agent") || - strings.Contains(outputMsg, "chat has no workspace agent") { + if strings.Contains(errMsg, "workspace has no running agent") || + strings.Contains(outputMsg, "workspace has no running agent") { foundUnavailableToolResult = true break } @@ -2533,7 +2533,7 @@ func TestStoppedWorkspaceWithPersistedAgentBindingDoesNotBlockChat(t *testing.T) require.Equal(t, codersdk.ChatMessagePartTypeToolResult, parts[0].Type) require.Equal(t, "execute", parts[0].ToolName) require.True(t, parts[0].IsError) - require.Contains(t, string(parts[0].Result), "chat has no workspace agent") + require.Contains(t, string(parts[0].Result), "workspace has no running agent") } func TestHeartbeatBumpsWorkspaceUsage(t *testing.T) {