Repository navigation
Conversation
setupTextStream subscribed to each reader without an error handler, so
when a sender disconnected mid-stream the errored reader's DataStreamError
was reported by RxJS as an unhandled observable error — rethrown globally
from a timer and surfacing as an uncaught DataStreamError that no
application code could catch.
Give the subscribe full next/complete/error handling and model the result
on TextStreamData via a new `status` field ('pending' | 'complete' |
'failed'), with the error exposed on failed entries. A clean close marks a
stream complete; any read error marks it failed while keeping the text
accumulated so far. No error type is special-cased here — consumers such
as useTranscriptions decide what a partial or failed stream means.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: cb1289a The changes in this PR will be included in the next version bump. This PR includes changesets to release 7 packages
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 |
Contributor
size-limit report 📦
|
Split the inline union into internal TextStreamDataCommon plus Pending/Complete/Failed variants and a Legacy (status?: never) member for backward compatibility, unioned as the exported TextStreamData. Variants stay unexported; only TextStreamData is public. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The chat text-stream handler in setupChat subscribed without an error handler, so a sender disconnecting mid-message errored the reader and RxJS rethrew it globally from a timer — the same uncaught DataStreamError that useTextStream had. Give that subscribe an error handler too. Every error is treated equally, with no special-casing by reason: text streams surface the failure through status, and chat has no such channel so it logs. The attachment byte-stream hang/leak is a separate failure mode and remains a follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rather than logging chat stream read errors, model them in the data the same way TextStreamData does. ReceivedChatMessage becomes a discriminated union with a status of 'pending' | 'complete' | 'failed' (error exposed on failed), plus a legacy member with no status so the other construction sites keep type-checking. The chat text-stream subscribe now emits pending as the message streams, complete on a clean close, and failed (keeping the text that arrived) when the read errors — which also stops RxJS from rethrowing the error globally as an uncaught exception. Every error is treated the same; no reason is special-cased. LegacyReceivedChatMessage becomes a type intersection since an interface cannot extend a union. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Without an explicit return type, `send`'s inferred type narrowed the `const receivedChatMsg: ReceivedChatMessage` to the no-status (legacy) member of the new discriminated union and emitted it expanded inline, which broke the react api-extractor report. Annotating the return as `Promise<ReceivedChatMessage>` restores the named reference. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1egoman
marked this pull request as ready for review
November 9, 2026 00:34
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Today, when a participant disconnects while one of its text streams is still open,
livekit-clienterrors the open reader with aDataStreamError(AbnormalEnd), by design.However, that means that when
setupTextStreamread each stream withfrom(reader).pipe(scan(...)).subscribe(next), which has no error handler, any errors that do get exposed get handled by this and end up as uncachable global errors.For voice-agent apps, an error fires whenever the agent leaves mid-segment (interrupted farewell, process exit, crash), which happens enough to be a nuisance and clog up error reporting.
This issue has already been attempted in #1426 but has been dormant for a few months. The existing solution aimed to fix this fully within
setupTextStream, which meant that it inherited a lot of additional complexity (ie, attachments) which made it quite large and complex. In this PR, instead I've opted to expose data stream error states up to the user viauseTextStream, and then consume this inuseTranscription. If more complex error handling is needed then that can all live inuseTranscriptionsinstead of the rx-heavysetupTextStream.Changes
TextStreamDatais now a discriminated union carrying astatus: 'pending' | 'complete' | 'failed'. Failed entries expose another propertyerrorwhich is the error that ended the read.next/complete/errorhandling:pending, accumulating text as before.complete; the text is whole.failed, keeping whatever text arrived. A stream that fails before emitting still surfaces as a failed entry rather than disappearing silently.failed. Any segment-level interpretation (e.g. treating a benignAbnormalEndafter a complete transcript as acceptable) belongs inuseTranscriptions, not core.Scope
Text / transcription streams only. Attachments were intentionally omitted, because
useTextStreamexposes onlystreamInfo.attachedStreamIds(IDs), never attachment bytes.Tests
New tests drive
setupTextStreamwith readers that complete normally, error mid-stream, and error before emitting: status transitionspending → complete, failed streams keep their accumulated text and expose the error, and nothing rethrows globally (the error-path tests fail on the unfixed code with the uncaught error). Full@livekit/components-coresuite (123) and@livekit/components-reactsuite (36) pass; both packages typecheck and build.