Skip to content

fix: pre-empt agent library stream error throws with sanitized finalize code#347

Draft
JeffOtano wants to merge 1 commit intomainfrom
claude/wonderful-tesla-Rrw5i
Draft

fix: pre-empt agent library stream error throws with sanitized finalize code#347
JeffOtano wants to merge 1 commit intomainfrom
claude/wonderful-tesla-Rrw5i

Conversation

@JeffOtano
Copy link
Copy Markdown
Owner

Summary

  • Root cause: @convex-dev/agent@0.6.1 stores stream events via saveStreamDeltas and processes them in its internal finalizeMessage V8 mutation using the AI SDK's process-ui-message-stream.ts. When a provider error event arrives in those stored deltas (e.g. a Gemini "high demand" 503), the mutation throws the raw provider error text. Because this mutation runs in a Convex V8 isolate independently from the calling action, Convex's built-in Sentry integration reports the throw before any action-level .catch() can intercept it — creating noise for every transient provider overload.
  • Fix: Add an onError callback to thread.streamText() in attemptStream that pre-emptively calls safeFinalizePending with the sanitized error code (e.g. "provider_overload") before result.text rejects. If our finalization runs first, the agent library's finalizeMessage finds the message already in "failed" state and skips delta processing — preventing the raw error from reaching the V8 throw path.
  • Module split: The error-reporting cluster (finalizePendingMessages, reportError, tryReportByok, and their safe wrappers + getFinalizeCodeForError) was extracted to a new resilienceReporting.ts to keep resilience.ts under the 400-line hard cap.

Why a proper fix, not a suppression

Prior attempts added the Gemini "high demand" substring to sentryBeforeSend.ts (Next.js Sentry filter), but that only filters the client-side throw. The V8 mutation throw goes through Convex's separate Sentry integration, which bypasses beforeSend entirely. The only correct fix is to prevent the throw from happening in the first place.

Test plan

  • convex/ai/resilienceStreamFailure.test.ts — 4 new tests added to "onError pre-emptive finalization" describe block:
    • onError fires with Gemini high-demand → finalizeMessage called with "provider_overload" (not raw text)
    • Raw provider error text is not exposed in the finalization code
    • onError fires with Claude overload → same "provider_overload" code
    • Happy path (no onError fired) → no spurious finalizeMessage calls
  • All 1256 backend tests pass (./node_modules/.bin/vitest run --project backend)
  • TypeScript clean (tsc --noEmit)
  • ESLint clean

https://claude.ai/code/session_01CJ3Ax6zGpqhHdFU36dwaLx


Generated by Claude Code

…ze code

@convex-dev/agent@0.6.1 processes saveStreamDeltas events in its internal
finalizeMessage mutation using the AI SDK stream processor. When a provider
error event (e.g. Gemini high-demand 503) arrives in those deltas, the mutation
throws the raw provider error text. Because this mutation runs in a Convex V8
isolate independently from the calling action, Convex reports the throw to
Sentry before any action-level catch handler can intercept it, creating noise
for every transient provider overload.

Fix: add an onError callback to thread.streamText() in attemptStream that
pre-emptively calls safeFinalizePending with the sanitized error code before
result.text rejects. If our finalization runs first, the agent library finds
the message already in "failed" state and skips delta processing, preventing
the raw provider error from reaching the V8 isolate throw path.

Also extract the error-reporting cluster to resilienceReporting.ts to keep
resilience.ts under the 400-line hard cap.

https://claude.ai/code/session_01CJ3Ax6zGpqhHdFU36dwaLx
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 225bf3cd-33b7-46a3-b8a8-e107b8b5b4bb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/wonderful-tesla-Rrw5i

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.

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.

2 participants