## TL;DR

Add a dedicated stop endpoint: closing the tab is a disconnect (generation continues), while the stop button should persist the partial response, cancel the work, and clear the active stream. Users expect it to continue; instead it restarts or vanishes. Check the useChat options for resume: true. Check the server for stream persistence (Redis via the resumable-stream package) and for POST/GET resume endpoints.

TL;DR: Check the useChat options for resume: true. Symptom: a page refresh or tab close kills a long generation. Users expect it to continue; instead it restarts or vanishes.

## Fix

1. Check the useChat options for resume: true.
 Expected: the value or setting is exactly right, nothing ambiguous.
2. Check the server for stream persistence (Redis via the resumable-stream package) and for POST/GET resume endpoints.
 Expected: the value or setting is exactly right, nothing ambiguous.
3. Fix (shape, per docs): 1.
 Expected: this specific failure stops.
4. Add a dedicated stop endpoint: closing the tab is a disconnect (generation continues), while the stop button should persist the partial response, cancel the work, and clear the active stream.
 Expected: this specific failure stops.
5. Then use the stop button and confirm the partial response is saved and no orphan stream remains.
 Expected: the request routes instead of erroring.
6. Only build it for generations long enough that losing one hurts.
 Expected: this specific failure stops.

## Details

Symptom: a page refresh or tab close kills a long generation. Users expect it to continue; instead it restarts or vanishes. Cause: by default, a client abort cancels the generation. There is no server-side stream to reconnect to, and no record of which stream belonged to the chat. Confirmation: 1. Absent, resumption is off by design. 2. Absent, there is nothing to resume from. Client: useChat({ id: chatId, messages, resume: true, transport }). On mount it auto-reconnects to the active stream for the chat. 2. Server: persist the outgoing UIMessage stream with the resumable-stream package into Redis; expose a GET resume endpoint the client polls via consumeSseStream. 3. 4. Track the active stream id per chat in your database so resume finds the right stream. Verification: start a long generation, refresh mid-stream, and confirm the UI reconnects and continues rather than restarting. Trade-off: this adds Redis and endpoint complexity.

## When to use

You hit exactly this: Diagnose aborted vs disconnected streams and resume after reload in Diagnose.

## When not to use

A different error, or the same symptom in a different tool. This page only covers the failure above.

## Compatibility

Diagnose.
