The Retry Keystroke Failed After Cancel: A Dead AbortSignal Retrospective
Description and use
Keyboard users can cancel a streaming request and then press Retry, but the retry button remains enabled while the underlying AbortController is already aborted, preventing a new request from starting and leaving the UI in a dead state. The fix is to create a new AbortController for each retry.
Problem
Keyboard users can cancel a streaming request and then press Retry, but the retry button remains enabled while the underlying AbortController is already aborted, preventing a new request from starting and leaving the UI in a dead state.
Outcome
The bug was caused by reusing the same AbortController across attempts. The fix is to create a new AbortController for each retry, ensuring the controller is not already aborted when starting a new fetch.
Workflow
- 1. Focus composer and submit prompt with Enter.
- 2. While status says generating, press Escape to cancel.
- 3. Observe focus moves to Stop (or hidden).
- 4. Tab to Retry and press Enter.
- 5. Verify that a new attempt starts, live region announces retry, composer is enabled, and focus lands on Stop or composer.
Evidence
Retry is not a click handler glued onto a cancelled bubble. Retry is a transition that must create a new attempt.
The first attempt had aborted, but Retry still held the same AbortController. signal.aborted was already true, so the next fetch never started.
- Record date: 2026-09-07T22:14:24.696Z