Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(core): prevent streamText abort unhandled rejections#1334

Merged
omeraplak merged 1 commit into
mainfrom
fix/streamtext-abort-lazy-promises
May 31, 2026
Merged

fix(core): prevent streamText abort unhandled rejections#1334
omeraplak merged 1 commit into
mainfrom
fix/streamtext-abort-lazy-promises

Conversation

@omeraplak
Copy link
Copy Markdown
Member

@omeraplak omeraplak commented May 31, 2026

PR Checklist

Please check if your PR fulfills the following requirements:

Bugs / Features

What is the current behavior?

Agent.streamText() eagerly materializes the AI SDK text, usage, and finishReason lazy result promises while constructing VoltAgent's wrapped stream result.

When a caller only consumes the stream, for example through toUIMessageStream(), and then aborts the run, those unconsumed promises can reject without handlers and emit global unhandledRejection events.

What is the new behavior?

VoltAgent preserves lazy access for text, usage, and finishReason on streamText() results. The sanitized text promise is now created only when result.text is accessed.

This keeps stream-only consumers from needing defensive .catch() handlers for fields they never read and aligns the wrapper more closely with AI SDK v6's lazy stream result contract.

fixes (issue): N/A

Notes for reviewers

Validation run locally:

  • pnpm --filter @voltagent/core build
  • pnpm --filter @voltagent/core test:single src/agent/agent.spec.ts -t "does not eagerly materialize lazy stream result promises"
  • pnpm exec biome check packages/core/src/agent/agent.ts packages/core/src/agent/agent.spec.ts .changeset/quiet-stream-abort.md

Summary by cubic

Fixes unhandled promise rejections when aborting Agent.streamText() by keeping text, usage, and finishReason lazy. Stream-only consumers (e.g., toUIMessageStream()) can abort safely, matching AI SDK v6’s lazy stream contract.

  • Bug Fixes
    • Do not eagerly create result promises; expose text, usage, and finishReason as getters on the wrapper.
    • Build sanitized text lazily only when result.text is accessed; contain guardrail finalizer errors so they don’t leak if text isn’t read.
    • Keep guardrail-aware textStream/fullStream behavior without forcing promise creation.

Written for commit 18c2b11. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

Bug Fixes

  • Resolved unhandled rejection errors when aborting stream operations. Agent.streamText() now uses lazy evaluation for stream result fields, creating promises only when explicitly accessed by callers. This prevents errors that previously occurred when aborting mid-stream after consuming partial results or specific stream derivatives.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 31, 2026

🦋 Changeset detected

Latest commit: 18c2b11

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@voltagent/core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 31, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d1dd8718-b2f8-49a4-aa11-6a96feaf2e49

📥 Commits

Reviewing files that changed from the base of the PR and between 41cad53 and 18c2b11.

📒 Files selected for processing (3)
  • .changeset/quiet-stream-abort.md
  • packages/core/src/agent/agent.spec.ts
  • packages/core/src/agent/agent.ts

📝 Walkthrough

Walkthrough

Agent.streamText() now defers sanitized text promise creation until the text is accessed, preventing unhandled rejections when callers abort without consuming the result. A centralized helper produces sanitized text by awaiting guardrail finalization (if present), preferring runner-sanitized text, and applying any bailedResult override. A test validates lazy evaluation, and changeset documents the fix.

Changes

Lazy Sanitized Text Promise

Layer / File(s) Summary
Lazy sanitized text promise helpers
packages/core/src/agent/agent.ts
createSanitizedTextPromise() centralizes sanitized text production by awaiting guardrail finalization if present, preferring runner.getSanitizedText() when non-empty, otherwise result.text, then applying bailedResult override from oc.systemContext. getSanitizedTextPromise() lazily initializes and memoizes that promise. sanitizedTextPromise variable becomes Promise<string> | undefined to enable on-demand creation.
Wiring lazy promise into stream lifecycle
packages/core/src/agent/agent.ts
onFinish callback now awaits getSanitizedTextPromise() for finalText. The returned StreamTextResultWithContext wrapper's text getter returns getSanitizedTextPromise() instead of a pre-captured value, aligning consumer access with finish logic.
Lazy evaluation test validation
packages/core/src/agent/agent.spec.ts
New test constructs a mock stream where text, usage, and finishReason are getters that increment counters on access. Verifies counters remain 0 immediately after agent.streamText(), then increment exactly once when those result properties are awaited.
Changeset documentation
.changeset/quiet-stream-abort.md
Documents that Agent.streamText() no longer triggers unhandled rejections on abort by preserving AI SDK v6 lazy getter behavior and deferring sanitized text promise creation until accessed.

🎯 2 (Simple) | ⏱️ ~12 minutes

🐰 A promise deferred, no more to fear,
Lazy getters dance, rejection won't appear,
When abort comes calling, streams stay serene,
The gentlest refactor I've ever seen!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main fix: preventing unhandled rejections during streamText abort operations by making lazy promises lazy.
Description check ✅ Passed The PR description comprehensively covers all template sections, clearly explains the problem and solution, includes test validation, changeset confirmation, and provides detailed reviewer notes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/streamtext-abort-lazy-promises

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@joggrbot

This comment has been minimized.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

Re-trigger cubic

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying voltagent with  Cloudflare Pages  Cloudflare Pages

Latest commit: 18c2b11
Status: ✅  Deploy successful!
Preview URL: https://b6908fb5.voltagent.pages.dev
Branch Preview URL: https://fix-streamtext-abort-lazy-pr.voltagent.pages.dev

View logs

@omeraplak omeraplak merged commit a1b4427 into main May 31, 2026
22 of 24 checks passed
@omeraplak omeraplak deleted the fix/streamtext-abort-lazy-promises branch May 31, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant