Skip to content

fix(ui): add missing optional chaining for activeResponse in makeRequest finally block#14260

Open
krislavten wants to merge 1 commit intovercel:mainfrom
krislavten:fix/active-response-optional-chaining
Open

fix(ui): add missing optional chaining for activeResponse in makeRequest finally block#14260
krislavten wants to merge 1 commit intovercel:mainfrom
krislavten:fix/active-response-optional-chaining

Conversation

@krislavten
Copy link
Copy Markdown

Bug

When two makeRequest calls run concurrently (e.g. sendMessage + resumeStream), the first to complete sets this.activeResponse = undefined in its finally block. The second call's finally block then crashes:

TypeError: Cannot read properties of undefined (reading 'state')

This is caused by an inconsistency in packages/ai/src/ui/chat.ts — the onFinish callback in the finally block uses a non-null assertion (!) for message but optional chaining (?.) for finishReason:

// Before (broken)
this.onFinish?.({
  message: this.activeResponse!.state.message,     // ← non-null assertion crashes
  // ...
  finishReason: this.activeResponse?.state.finishReason,  // ← has ?. but .state doesn't
});

Fix

  • Replace this.activeResponse!.state.message with this.activeResponse?.state?.message
  • Add ?. to .state?.finishReason for full safety
  • Update ChatOnFinishCallback type to allow message: UI_MESSAGE | undefined
// After (safe)
this.onFinish?.({
  message: this.activeResponse?.state?.message,
  // ...
  finishReason: this.activeResponse?.state?.finishReason,
});

Affected Versions

This bug exists from at least 6.0.x through the current 7.0.0-beta — any version with the AbstractChat class and its makeRequest method.

Reproduction

  1. Create a chat instance with onFinish callback
  2. Trigger two concurrent makeRequest calls (e.g. call sendMessage() and resumeStream() without awaiting the first)
  3. The first to resolve sets this.activeResponse = undefined
  4. The second hits the finally block → TypeError

Test Plan

  • All 26 existing tests in chat.test.ts pass
  • Full monorepo build succeeds (69/69 tasks)
  • Lint (ultracite) passes via pre-commit hook

…est finally block

When two `makeRequest` calls run concurrently (e.g. `sendMessage` + `resumeStream`),
the first to complete sets `this.activeResponse = undefined` in its finally block.
The second call's finally block then crashes with:
`TypeError: Cannot read properties of undefined (reading 'state')`

This happened because `this.activeResponse!.state.message` used a non-null assertion
instead of optional chaining, while `this.activeResponse?.state.finishReason` on the
very next property already used `?.` — an inconsistency.

Changes:
- Replace `this.activeResponse!.state.message` with `this.activeResponse?.state?.message`
- Add `?.` to `this.activeResponse?.state?.finishReason` for consistency
- Update `ChatOnFinishCallback` type to reflect that `message` can be `undefined`
@tigent tigent bot added ai/ui anything UI related bug Something isn't working as documented labels Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai/ui anything UI related bug Something isn't working as documented

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant