Skip to content

Fixed cancelled ReadAsync/WriteAsync throwing the exception of the native operation instead of an OperationCanceledException - #2067

Open
adutton wants to merge 1 commit into
dlemstra:mainfrom
adutton:fix-cancelled-async-stream-operations
Open

Fixed cancelled ReadAsync/WriteAsync throwing the exception of the native operation instead of an OperationCanceledException#2067
adutton wants to merge 1 commit into
dlemstra:mainfrom
adutton:fix-cancelled-async-stream-operations

Conversation

@adutton

@adutton adutton commented Jul 27, 2026

Copy link
Copy Markdown

Description

Fixes #2066.

Since 14.15.0 (when the AsyncStreamWrapper was introduced), cancelling ReadAsync/WriteAsync stream operations throws the exception of the native operation instead of an OperationCanceledException. For a cancelled JPEG write that is:

ImageMagick.MagickCorruptImageErrorException: Output file write error --- out of disk space? `' @ error/jpeg.c/JPEGErrorHandler/614

The cause: when the token is cancelled, the async pump loops set _exceptionThrown and the blocked native callback reports a failed read/write, which makes the native coder raise an error that propagates out of the action task. The existing conversion at the end of ReadAsync(Action, ...)/WriteAsync(Action, ...):

if (_exceptionThrown)
    cancellationToken.ThrowIfCancellationRequested();

is unreachable in that case because await Task.WhenAll(...) rethrows the action task's exception first.

This change wraps the Task.WhenAll in a try/catch when (_exceptionThrown) that calls ThrowIfCancellationRequested() (and rethrows the original exception when the failure was not caused by a cancellation, preserving the current behavior for stream exceptions).

The existing cancellation tests did not catch this because their test actions ignore the failed read/write result; the native coders throw in that situation. The new tests mirror the existing ones but throw from the action when the operation fails, plus end-to-end tests on MagickImage.ReadAsync(Stream)/WriteAsync(Stream) with a cancelled token.

Verified with the Q8 x64 net8.0 test suite on Windows: all tests pass with the fix; the four new tests fail without it (they reproduce the exact exceptions from #2066).

…tive operation instead of an OperationCanceledException (dlemstra#2066).
@CLAassistant

CLAassistant commented Jul 27, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants