dotnet/runtime · error · Error

BrowserHttpWriteStream.Rejected

Error message

BrowserHttpWriteStream.Rejected

What it means

httpTransformStreamWrite() writes a chunk to a WritableStreamDefaultWriter used as the request body for a streaming fetch. If awaiting streamWriter.ready or streamWriter.write(copy) rejects (the underlying stream errored or the server aborted the upload), the original error is swallowed and replaced with this generic marker. The .NET side sees 'BrowserHttpWriteStream.Rejected'.

Solutions

  1. Wrap the streaming request in a try/catch and surface the cancellation/network failure to the user; the generic message means the stream was rejected, not the request payload itself.
  2. Check httpSupportsStreamingRequest() before attempting a streaming upload; if false, fall back to buffering the body (httpFetchBytes) instead of httpFetchStream.
  3. Verify the AbortController wasn't triggered prematurely (e.g. a timeout set too short) before the upload completed.
  4. On Safari or browsers without duplex fetch support, use a buffered (non-streaming) request body.

Example fix

// before: assume streaming upload always works
using var content = new StreamContent(largeStream);
await httpClient.PostAsync(url, content, ct);

// after: feature-detect and fall back
if (runtime.INTERNAL.httpSupportsStreamingRequest()) {
    // streaming upload
} else {
    // buffer the body into a byte[] and use HttpContent
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Feature-detect streaming request support before choosing the upload path.
import { httpSupportsStreamingRequest } from "./http";

function planUpload(body: Uint8Array): "stream" | "buffer" {
  return httpSupportsStreamingRequest() ? "stream" : "buffer";
}

Type guard

null

Try / catch

try {
  await runtime.INTERNAL.httpFetchStream(controller, url, hNames, hVals, oNames, oVals);
} catch (e) {
  if (e?.message === "BrowserHttpWriteStream.Rejected") {
    // transport rejected the stream: network/abort/unsupported duplex
    // fall back to a buffered request or surface to the user
  } else throw e;
}

Prevention

When it happens

Trigger: Calling HttpClient with a streaming request body (httpFetchStream) and writing a chunk whose underlying writer rejected. Triggers: server closed the connection mid-upload, the AbortController fired, the browser rejected the duplex stream (e.g. unsupported in Safari), or a network failure during request body upload.

Common situations: Uploading large/streaming request bodies with HttpClient.PostAsync + StreamContent; Safari which does not fully support duplex fetch streams; server-side early response/reset (RST_STREAM) that aborts the request writer; AbortController token triggered during upload.

Related errors


AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10). Data as JSON: /api/errors/07caaa5837523574. Report an issue: GitHub.

Appendix: source

Thrown at src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/http.ts:110

    } catch (err) {
        // ignore
    }
}

export function httpTransformStreamWrite(controller: HttpController, bufferPtr: VoidPtr, bufferLength: number): ControllablePromise<void> {
    commonAsserts(controller);
    dotnetAssert.check(bufferLength > 0, "expected bufferLength > 0");
    // the bufferPtr is pinned by the caller
    const view = new Span(bufferPtr, bufferLength, MemoryViewType.Byte);
    const copy = view.slice() as Uint8Array;
    return wrapAsCancelablePromise(async () => {
        dotnetAssert.check(controller.streamWriter, "expected streamWriter");
        dotnetAssert.check(controller.responsePromise, "expected fetch promise");
        try {
            await controller.streamWriter.ready;
            await controller.streamWriter.write(copy);
        } catch (ex) {
            throw new Error("BrowserHttpWriteStream.Rejected");
        }
    });
}

export function httpTransformStreamClose(controller: HttpController): ControllablePromise<void> {
    dotnetAssert.check(controller, "expected controller");
    return wrapAsCancelablePromise(async () => {
        dotnetAssert.check(controller.streamWriter, "expected streamWriter");
        dotnetAssert.check(controller.responsePromise, "expected fetch promise");
        try {
            await controller.streamWriter.ready;
            await controller.streamWriter.close();
        } catch (ex) {
            throw new Error("BrowserHttpWriteStream.Rejected");
        }
    });
}

View on GitHub (pinned to 60108ba66e)