dotnet/runtime · warning · Error

OperationCanceledException

Error message

OperationCanceledException

What it means

While reading a streamed response in httpGetStreamedResponseBytes, once the reader reports chunk.done, if controller.isAborted is true the interop throws 'OperationCanceledException' so the .NET caller receives a proper cancellation rather than a clean zero-byte EOF. This maps to .NET's OperationCanceledException semantics.

Source

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

    const view = new Span(bufferPtr, bufferLength, MemoryViewType.Byte);
    return wrapAsCancelablePromise(async () => {
        await controller.responsePromise;
        dotnetAssert.check(controller.response, "expected response");
        if (!controller.response.body) {
            // in FF when the verb is HEAD, the body is null
            return 0;
        }
        if (!controller.streamReader) {
            controller.streamReader = controller.response.body.getReader();
            muteUnhandledRejection(controller.streamReader.closed);
        }
        if (!controller.currentStreamReaderChunk || controller.currentBufferOffset === undefined) {
            controller.currentStreamReaderChunk = await controller.streamReader.read();
            controller.currentBufferOffset = 0;
        }
        if (controller.currentStreamReaderChunk.done) {
            if (controller.isAborted) {
                throw new Error("OperationCanceledException");
            }
            return 0;
        }

        const remainingSource = controller.currentStreamReaderChunk.value.byteLength - controller.currentBufferOffset;
        dotnetAssert.check(remainingSource > 0, "expected remainingSource to be greater than 0");

        const bytesCopied = Math.min(remainingSource, view.byteLength);
        const sourceView = controller.currentStreamReaderChunk.value.subarray(controller.currentBufferOffset, controller.currentBufferOffset + bytesCopied);
        view.set(sourceView, 0);
        controller.currentBufferOffset += bytesCopied;
        if (remainingSource == bytesCopied) {
            controller.currentStreamReaderChunk = undefined;
        }

        return bytesCopied;
    });
}

View on GitHub (pinned to 290d5ab72c)

Solutions

  1. Treat this as expected cancellation — handle OperationCanceledException in .NET rather than as a fault.
  2. If unexpected, check for an overly aggressive CancellationTokenSource timeout.
  3. Avoid aborting a controller whose response stream has already completed.

Example fix

// before: cancellation surfaces as an unhandled error

// after: handle expected cancellation
try { await responseStream.ReadAsync(buffer, ct); }
catch (OperationCanceledException) when (ct.IsCancellationRequested) { /* expected */ }
Defensive patterns

Strategy: try-catch

Try / catch

try { await responseStream.ReadAsync(buffer, ct); }
catch (OperationCanceledException) when (ct.IsCancellationRequested) {
  // expected cancellation, not a fault
}

Prevention

When it happens

Trigger: The response stream completed (or was cut) at the same moment the request was aborted via httpAbort/AbortController, so the interop surfaces cancellation to the .NET HttpClient.

Common situations: A CancellationToken fires exactly as the download stream ends; a client-side timeout triggering near response completion; explicit user cancel of a streaming download.

Related errors


AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06). Data as JSON: /api/errors/20a5b2d2a518f0bc. Report an issue: GitHub.