@@ -9,15 +9,22 @@ import type {
99import { IdentityTransform } from './identity_transform.js' ;
1010
1111/**
12- * Check if error is related to reader.read after release lock
12+ * Check if error is related to stream cleanup operations.
13+ *
14+ * These errors are expected when calling reader.read() after releaseLock()
15+ * or when writing to already closed streams during cleanup:
1316 *
1417 * Invalid state: Releasing reader
1518 * Invalid state: The reader is not attached to a stream
19+ * Invalid state: Controller is already closed
20+ * Invalid state: WritableStream is closed
1621 */
1722export function isStreamReaderReleaseError ( e : unknown ) {
1823 const allowedMessages = [
1924 'Invalid state: Releasing reader' ,
2025 'Invalid state: The reader is not attached to a stream' ,
26+ 'Controller is already closed' ,
27+ 'WritableStream is closed' ,
2128 ] ;
2229
2330 if ( e instanceof TypeError ) {
@@ -66,18 +73,27 @@ export class DeferredReadableStream<T> {
6673 await this . writer . write ( value ) ;
6774 }
6875 } catch ( e ) {
69- // skip source detach related errors
76+ // skip stream cleanup related errors
7077 if ( isStreamReaderReleaseError ( e ) ) return ;
78+
7179 sourceError = e ;
7280 } finally {
7381 // any other error from source will be propagated to the consumer
7482 if ( sourceError ) {
75- this . writer . abort ( sourceError ) ;
83+ try {
84+ this . writer . abort ( sourceError ) ;
85+ } catch ( e ) {
86+ // ignore if writer is already closed
87+ }
7688 return ;
7789 }
7890
7991 // release lock so this.stream.getReader().read() will terminate with done: true
80- this . writer . releaseLock ( ) ;
92+ try {
93+ this . writer . releaseLock ( ) ;
94+ } catch ( e ) {
95+ // ignore if writer lock is already released
96+ }
8197
8298 // we only close the writable stream after done
8399 try {
@@ -98,7 +114,8 @@ export class DeferredReadableStream<T> {
98114 */
99115 async detachSource ( ) {
100116 if ( ! this . isSourceSet ) {
101- throw new Error ( 'Source not set' ) ;
117+ // No-op if source was never set - this is a common case during cleanup
118+ return ;
102119 }
103120
104121 // release lock will make any pending read() throw TypeError
0 commit comments