louthy/language-ext · warning · OperationCanceledException

OperationCanceledException

Error message

OperationCanceledException

What it means

Iterable.AsEnumerableIO returns an IO-wrapped IEnumerable whose iterator checks env.Token before yielding each Prefix element; when cancellation is requested it throws OperationCanceledException. This is cooperative cancellation: the enumeration aborts as soon as the token from EnvIO is signaled, so the consumer must be prepared for the sequence to terminate via this exception rather than completing.

Solutions

  1. Catch OperationCanceledException around enumeration and treat it as expected cancellation, not a failure.
  2. Check env.Token.IsCancellationRequested before/while consuming and stop gracefully.
  3. Use IO.cancel or run the whole IO under the caller's token semantics instead of mixing tokens.
  4. If cancellation is not desired, run with a CancellationToken.None-based EnvIO.

Example fix

// before
foreach (var x in iterable.AsEnumerableIO().Run(env)) Process(x); // throws on cancel

// after
try
{
    foreach (var x in iterable.AsEnumerableIO().Run(env)) Process(x);
}
catch (OperationCanceledException) when (env.Token.IsCancellationRequested)
{
    // graceful cancellation
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (env.Token.IsCancellationRequested) return; // stop before enumerating

Type guard

static bool CanEnumerate(EnvIO env) => !env.Token.IsCancellationRequested;

Try / catch

try { foreach (var x in seq) { ... } }
catch (OperationCanceledException) when (env.Token.IsCancellationRequested) { /* expected cancellation */ }

Prevention

When it happens

Trigger: Enumerating the IEnumerable returned by iterable.AsEnumerableIO().Run(...) after (or while) the EnvIO CancellationToken is cancelled; consuming the sequence lazily after a timeout or shutdown signal fires.

Common situations: Host cancellation/shutdown mid-enumeration, ASP.NET request abort tokens flowing into EnvIO, or a CancellationTokenSource cancelled because a timeout elapsed while the consumer was still pulling items.

Related errors


AI-assisted analysis of louthy/language-ext@2f0e362824 (2026-09-15). Data as JSON: /api/errors/6732fb7ab97ef62d. Report an issue: GitHub.

Appendix: source

Thrown at LanguageExt.Core/Immutable Collections/Iterable/DSL/Iterable.Add.cs:29

        Source.IsAsync;
    
    public override IO<int> CountIO() =>
        Source.CountIO().Map(c => Prefix.Count + c + Postfix.Count);

    public override Iterable<A> Add(A item) =>
        new IterableAdd<A>(Prefix, Source, (SeqStrict<A>)Postfix.Add(item));

    public override Iterable<A> Cons(A item) =>
        new IterableAdd<A>((SeqStrict<A>)Prefix.Cons(item), Source, Postfix);

    public override IO<IEnumerable<A>> AsEnumerableIO()
    {
        return IO.lift(go);
        IEnumerable<A> go(EnvIO env)
        {
            foreach (var x in Prefix)
            {
                if (env.Token.IsCancellationRequested) throw new OperationCanceledException();
                yield return x;
            }

            foreach (var x in Source.AsEnumerable(env.Token))
            {
                if(env.Token.IsCancellationRequested) throw new OperationCanceledException();
                yield return x;
            }

            foreach (var x in Postfix)
            {
                if (env.Token.IsCancellationRequested) throw new OperationCanceledException();
                yield return x;
            }
        }
    }

    public override IO<IAsyncEnumerable<A>> AsAsyncEnumerableIO()

View on GitHub (pinned to 2f0e362824)