{"record":{"id":"cfab00f64b10808b","repo":"dotnet/runtime","slug":"operationcanceledexception","errorCode":null,"errorMessage":"OperationCanceledException","messagePattern":"OperationCanceledException","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/mono/browser/runtime/http.ts","lineNumber":260,"sourceCode":"    const view = new Span(bufferPtr, bufferLength, MemoryViewType.Byte);\n    return wrap_as_cancelable_promise(async () => {\n        await controller.responsePromise;\n        mono_assert(controller.response, \"expected response\");\n        if (!controller.response.body) {\n            // in FF when the verb is HEAD, the body is null\n            return 0;\n        }\n        if (!controller.streamReader) {\n            controller.streamReader = controller.response.body.getReader();\n            mute_unhandledrejection(controller.streamReader.closed);\n        }\n        if (!controller.currentStreamReaderChunk || controller.currentBufferOffset === undefined) {\n            controller.currentStreamReaderChunk = await controller.streamReader.read();\n            controller.currentBufferOffset = 0;\n        }\n        if (controller.currentStreamReaderChunk.done) {\n            if (controller.isAborted) {\n                throw new Error(\"OperationCanceledException\");\n            }\n            return 0;\n        }\n\n        const remaining_source = controller.currentStreamReaderChunk.value.byteLength - controller.currentBufferOffset;\n        mono_assert(remaining_source > 0, \"expected remaining_source to be greater than 0\");\n\n        const bytes_copied = Math.min(remaining_source, view.byteLength);\n        const source_view = controller.currentStreamReaderChunk.value.subarray(controller.currentBufferOffset, controller.currentBufferOffset + bytes_copied);\n        view.set(source_view, 0);\n        controller.currentBufferOffset += bytes_copied;\n        if (remaining_source == bytes_copied) {\n            controller.currentStreamReaderChunk = undefined;\n        }\n\n        return bytes_copied;\n    });\n}","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/mono/browser/runtime/http.ts#L242-L278","documentation":"Thrown by http_wasm_get_streamed_response_bytes in http.ts when the response body reader reports done (currentStreamReaderChunk.done) and controller.isAborted is true. This converts an abort-after-stream-end into an OperationCanceledException so managed code sees the cancellation rather than a clean zero-byte read.","triggerScenarios":"Reading a streamed HTTP response with HttpClient.SendAsync(HttpCompletionOption.ResponseHeadersRead) and the CancellationToken is cancelled, or HttpClient is disposed, while the response body is still being drained; the server completes the stream exactly when the client aborts.","commonSituations":"User navigates away during a large download; a CancellationTokenSource cancels a long streaming GET; component dispose cancels an in-flight HttpClient call.","solutions":["Catch OperationCanceledException (or its HttpRequestException wrapper) on the managed streaming call and treat it as cancellation, not a fault.","Avoid disposing HttpClient or cancelling the token while a streamed read loop is in progress unless you intend to cancel.","If you need partial results, copy bytes read before the cancellation into your own buffer."],"exampleFix":"// before: unhandled cancellation on streamed read\ntry { await foreach (var b in response.Content.ReadAsStreamAsync()) { ... } }\ncatch { throw; }\n// after: handle cancellation explicitly\ntry { await foreach (var b in stream.WithCancellation(token)) { ... } }\ncatch (OperationCanceledException) { /* expected on abort */ }","handlingStrategy":"try-catch","validationCode":"// pass the token and check before each read\nif (token.IsCancellationRequested) return;","typeGuard":null,"tryCatchPattern":"try {\n  await foreach (var chunk in response.Content.ReadAsStreamAsync(token)) { ... }\n} catch (OperationCanceledException) {\n  // the streamed response was aborted; this is expected on cancellation\n}","preventionTips":["Always pass the CancellationToken to streaming reads (WithCancellation).","Catch OperationCanceledException separately from other HTTP errors.","Do not dispose HttpClient while a streamed read loop is still draining."],"tags":["http","streaming","cancellation","download"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}