louthy/language-ext · info · OperationCanceledException
OperationCanceledException
Error message
OperationCanceledException
What it means
Iterable.Enumerable.AsEnumerableIO wraps a plain IEnumerable<A> in an IO.lift whose iterator checks env.Token.IsCancellationRequested before yielding every element, throwing OperationCanceledException when cancelled. This makes any derived IO pipeline (CountIO, Map, Filter, Reverse, AsAsyncEnumerableIO all call it) cancellation-aware. It is cooperative cancellation, not an unexpected fault.
Solutions
- Catch OperationCanceledException where the IO is run and handle shutdown explicitly
- Pass a different or non-cancelled token: io.Run(EnvIO.New(newCts.Token))
- Use CancellationToken.IsCancellationRequested in your own loop with FoldWhileIO to stop before the library throws
- If cancellation was accidental, audit the token source lifetime (e.g. using-blocks that dispose/cancel too early)
Example fix
// before
var count = iterable.CountIO().Run(EnvIO.New(token));
// after
int count;
try { count = iterable.CountIO().Run(EnvIO.New(token)); }
catch (OperationCanceledException) { count = -1; /* cancelled */ } Defensive patterns
Strategy: try-catch
Validate before calling
if (env.Token.IsCancellationRequested) { /* abort before running the pipeline */ } Try / catch
try { var r = iterable.CountIO().Run(EnvIO.New(token)); }
catch (OperationCanceledException) { /* handle cancellation */ } Prevention
- Scope cancellation tokens to the logical operation, not to using-block lifetimes
- Handle cancellation once at the pipeline boundary rather than per-call
- Use FoldWhile/While predicates for early exit instead of cancellation
When it happens
Trigger: Enumerating the IO<IEnumerable<A>> from Iterable.Wrap/creation's AsEnumerableIO (directly or via CountIO, AsAsyncEnumerableIO, Reverse, Map, Filter) after the EnvIO token is cancelled; the throw occurs at line 26 before the first yield of each element.
Common situations: Cancelling a Map/Filter/Count pipeline on HTTP request abort; a timeout token expiring while a large enumerable is being processed; shared CancellationTokenSource cancelled by another subsystem mid-iteration.
Related errors
- OperationCanceledException
- OperationCanceledException
- OperationCanceledException
- OperationCanceledException
- OperationCanceledException
AI-assisted analysis of louthy/language-ext@2f0e362824 (2026-09-15).
Data as JSON: /api/errors/68d6e40cff23d6c8.
Report an issue: GitHub.
Appendix: source
Thrown at LanguageExt.Core/Immutable Collections/Iterable/DSL/Iterable.Enumerable.cs:26
sealed class IterableEnumerable<A>(IO<IEnumerable<A>> runEnumerable) : Iterable<A>
{
internal override bool IsAsync =>
false;
public override IO<int> CountIO() =>
AsEnumerableIO().Map(xs => xs.Count());
public override IO<IEnumerable<A>> AsEnumerableIO()
{
// This makes a regular IEnumerable cancellable.
return IO.lift(env => go(env, runEnumerable));
static IEnumerable<A> go(EnvIO env, IO<IEnumerable<A>> run)
{
var xs = run.Run(env);
foreach (var x in xs)
{
if (env.Token.IsCancellationRequested) throw new OperationCanceledException();
yield return x;
}
}
}
public override IO<IAsyncEnumerable<A>> AsAsyncEnumerableIO() =>
AsEnumerableIO().Map(xs => xs.ToAsyncEnumerable());
public override Iterable<A> Reverse() =>
new IterableEnumerable<A>(AsEnumerableIO().Map(xs => xs.Reverse()));
public override Iterable<B> Map<B>(Func<A, B> f) =>
new IterableEnumerable<B>(AsEnumerableIO().Map(xs => xs.Select(f)));
public override Iterable<A> Filter(Func<A, bool> f) =>
new IterableEnumerable<A>(AsEnumerableIO().Map(xs => xs.Where(f)));
public override IO<S> FoldWhileIO<S>(Func<A, Func<S, S>> f, Func<(S State, A Value), bool> predicate, S initialState) => View on GitHub (pinned to 2f0e362824)