Skip to content

Commit 01f6dc2

Browse files
romanlutzCopilot
andauthored
Fix chat UI stuck loading after first message send failure (microsoft#2110)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 5505aa2 commit 01f6dc2

2 files changed

Lines changed: 37 additions & 1 deletion

File tree

frontend/e2e/errors.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,29 @@ test.describe("Error: backend 500 on send message", () => {
264264
// The failed text should be restored in the input for easy re-send
265265
await expect(input).toHaveValue("This should fail", { timeout: 5000 });
266266
});
267+
268+
test("should recover cleanly when the first send fails", async ({ page }) => {
269+
await mockAllAPIs(page, async (route) => {
270+
await route.fulfill({
271+
status: 500,
272+
contentType: "application/json",
273+
body: JSON.stringify({ detail: "Internal server error" }),
274+
});
275+
});
276+
277+
await page.goto("/");
278+
await activateMockTarget(page);
279+
280+
const input = page.getByRole("textbox");
281+
await input.fill("First send fails");
282+
await page.getByRole("button", { name: /send/i }).click();
283+
284+
await expect(page.getByText(/Internal server error/i)).toBeVisible({
285+
timeout: 10000,
286+
});
287+
await expect(page.getByTestId("loading-state")).toHaveCount(0);
288+
await expect(input).toHaveValue("First send fails", { timeout: 5000 });
289+
});
267290
});
268291

269292
// ---------------------------------------------------------------------------

frontend/src/components/Chat/ChatWindow.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,21 @@ export default function ChatWindow({
347347
setLoadedConversationId(effectiveConvId!)
348348
}
349349
} catch (err) {
350+
const viewedConversationId = viewedConvRef.current
351+
const isViewingFailedConversation = viewedConversationId === sendConvId
352+
|| viewedConversationId === (activeConversationId ?? conversationId)
353+
|| (viewedConversationId == null && sendConvId !== '__pending__')
354+
350355
// Only show error in UI if user is still on this conversation
351-
if (viewedConvRef.current === sendConvId || viewedConvRef.current === (activeConversationId ?? conversationId)) {
356+
if (isViewingFailedConversation) {
357+
// Mark the viewed conversation as loaded so first-send failures do not
358+
// get stuck behind the "Loading conversation..." placeholder.
359+
if (viewedConversationId) {
360+
setLoadedConversationId(viewedConversationId)
361+
} else if (sendConvId !== '__pending__') {
362+
setLoadedConversationId(sendConvId)
363+
}
364+
352365
const apiError = toApiError(err)
353366
let description: string
354367
if (apiError.isNetworkError) {

0 commit comments

Comments
 (0)