louthy/language-ext · warning · OperationCanceledException
OperationCanceledException
Error message
OperationCanceledException
What it means
AsEnumerable creates an EnvIO from the given token and throws OperationCanceledException inside the yield loop when the token is cancelled while a consumer pulls elements. Because it is an iterator, the exception is deferred: it fires during MoveNext on the enumerable, not at the AsEnumerable call itself.
Solutions
- Enumerate the result promptly and pass a token whose lifetime covers the whole enumeration.
- Catch OperationCanceledException around the foreach that consumes the enumerable.
- Materialize with ToList()/ToArray() while the token is still valid if you need the data afterwards.
- Use the default token (CancellationToken.None) when no cancellation semantics are required.
Example fix
// before var xs = iterable.AsEnumerable(requestAbortedToken); SaveToDb(xs.ToList()); // enumerated later, token already cancelled // after var xs = iterable.AsEnumerable(requestAbortedToken).ToList(); // enumerate now SaveToDb(xs);
Defensive patterns
Strategy: try-catch
Validate before calling
if (token.IsCancellationRequested) throw new OperationCanceledException(token); // check before enumerating
Try / catch
try
{
foreach (var x in iterable.AsEnumerable(token))
Process(x);
}
catch (OperationCanceledException) when (token.IsCancellationRequested)
{
// enumeration cancelled
} Prevention
- Remember iterator exceptions fire during MoveNext, not at AsEnumerable
- Enumerate promptly or materialize with ToList while the token is valid
- Don't cache enumerables tied to request-scoped tokens
- Catch OperationCanceledException around any foreach consuming AsEnumerable(token)
When it happens
Trigger: Enumerating the IEnumerable returned by AsEnumerable(token) after that token is cancelled; also triggered indirectly by Choose, IterIO, EqualsIO, and iterA, all of which call AsEnumerable internally.
Common situations: LINQ pipelines that enumerate lazily after a request was aborted; holding the enumerable longer than the token's lifetime (e.g. token from a disposed request context); iterating a very large iterable past a timeout.
Related errors
- OperationCanceledException
- OperationCanceledException
- OperationCanceledException
- OperationCanceledException
- OperationCanceledException
AI-assisted analysis of louthy/language-ext@2f0e362824 (2026-09-15).
Data as JSON: /api/errors/73b75dd2a2f85883.
Report an issue: GitHub.
Appendix: source
Thrown at LanguageExt.Core/Immutable Collections/Iterable/Iterable.cs:74
CountIO().Run();
/// <summary>
/// Number of items in the sequence.
/// </summary>
[Pure]
public abstract IO<int> CountIO();
/// <summary>
/// Stream as an enumerable
/// </summary>
[Pure]
public IEnumerable<A> AsEnumerable(CancellationToken token = default)
{
using var env = EnvIO.New(token: token);
var xs = AsEnumerableIO().Run();
foreach (var x in xs)
{
if(env.Token.IsCancellationRequested) throw new OperationCanceledException();
yield return x;
}
}
/// <summary>
/// Stream as an enumerable
/// </summary>
[Pure]
public abstract IO<IEnumerable<A>> AsEnumerableIO();
/// <summary>
/// Stream as an enumerable
/// </summary>
[Pure]
public async IAsyncEnumerable<A> AsAsyncEnumerable([EnumeratorCancellation] CancellationToken token = default)
{
using var env = EnvIO.New(token: token);
var xs = await AsAsyncEnumerableIO().RunAsync(env);View on GitHub (pinned to 2f0e362824)