Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .changeset/fix-activeresponse-finally.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
'ai': patch
---

Fix TypeError in onFinish when activeResponse is undefined

Fixed a bug where `this.activeResponse` could be undefined in the finally block of `makeRequest`, causing a TypeError when calling `onFinish`. This happened when:

1. An error was thrown before `this.activeResponse` was assigned
2. A concurrent `makeRequest` call overwrote `this.activeResponse`

The fix uses a local variable to capture `activeResponse` at the start of the try block, ensuring it's available in the finally block regardless of concurrent operations.

Fixes #8477
35 changes: 23 additions & 12 deletions packages/ai/src/ui/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -590,8 +590,13 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
let isDisconnect = false;
let isError = false;

// Capture activeResponse locally to ensure it's available in finally block.
// Using `this.activeResponse` in finally could be undefined if error thrown
// before assignment, or overwritten by concurrent makeRequest calls.
let activeResponse: ActiveResponse<UI_MESSAGE> | undefined;

try {
const activeResponse = {
activeResponse = {
state: createStreamingUIMessageState({
lastMessage: this.state.snapshot(lastMessage),
messageId: this.generateId(),
Expand Down Expand Up @@ -706,17 +711,23 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {

this.setStatus({ status: 'error', error: err as Error });
} finally {
try {
this.onFinish?.({
message: this.activeResponse!.state.message,
messages: this.state.messages,
isAbort,
isDisconnect,
isError,
finishReason: this.activeResponse?.state.finishReason,
});
} catch (err) {
console.error(err);
// Use local activeResponse instead of this.activeResponse to avoid
// TypeError when activeResponse is undefined (error before assignment)
// or overwritten (concurrent makeRequest calls).
// See: https://github.com/vercel/ai/issues/8477
if (activeResponse) {
try {
this.onFinish?.({
message: activeResponse.state.message,
messages: this.state.messages,
isAbort,
isDisconnect,
isError,
finishReason: activeResponse.state.finishReason,
});
} catch (err) {
console.error(err);
}
}

this.activeResponse = undefined;
Expand Down