{"record":{"id":"68d6e40cff23d6c8","repo":"louthy/language-ext","slug":"operationcanceledexception-iterable-enumerable","errorCode":null,"errorMessage":"OperationCanceledException","messagePattern":"OperationCanceledException","errorType":"exception","errorClass":"OperationCanceledException","httpStatus":null,"severity":"info","filePath":"LanguageExt.Core/Immutable Collections/Iterable/DSL/Iterable.Enumerable.cs","lineNumber":26,"sourceCode":"\nsealed class IterableEnumerable<A>(IO<IEnumerable<A>> runEnumerable) : Iterable<A>\n{\n    internal override bool IsAsync =>\n        false;\n    \n    public override IO<int> CountIO() =>\n        AsEnumerableIO().Map(xs => xs.Count());\n\n    public override IO<IEnumerable<A>> AsEnumerableIO()\n    {\n        // This makes a regular IEnumerable cancellable.\n        return IO.lift(env => go(env, runEnumerable));\n        static IEnumerable<A> go(EnvIO env, IO<IEnumerable<A>> run)\n        {\n            var xs = run.Run(env);\n            foreach (var x in xs)\n            {\n                if (env.Token.IsCancellationRequested) throw new OperationCanceledException();\n                yield return x;\n            }\n        }\n    }\n\n    public override IO<IAsyncEnumerable<A>> AsAsyncEnumerableIO() =>\n        AsEnumerableIO().Map(xs => xs.ToAsyncEnumerable());\n\n    public override Iterable<A> Reverse() =>\n        new IterableEnumerable<A>(AsEnumerableIO().Map(xs => xs.Reverse()));\n\n    public override Iterable<B> Map<B>(Func<A, B> f) =>\n        new IterableEnumerable<B>(AsEnumerableIO().Map(xs => xs.Select(f)));\n\n    public override Iterable<A> Filter(Func<A, bool> f) =>\n        new IterableEnumerable<A>(AsEnumerableIO().Map(xs => xs.Where(f)));\n\n    public override IO<S> FoldWhileIO<S>(Func<A, Func<S, S>> f, Func<(S State, A Value), bool> predicate, S initialState) => ","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/louthy/language-ext/blob/2f0e3628242889774d4141960a35671a0280051f/LanguageExt.Core/Immutable Collections/Iterable/DSL/Iterable.Enumerable.cs#L8-L44","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before\nvar count = iterable.CountIO().Run(EnvIO.New(token));\n// after\nint count;\ntry { count = iterable.CountIO().Run(EnvIO.New(token)); }\ncatch (OperationCanceledException) { count = -1; /* cancelled */ }","handlingStrategy":"try-catch","validationCode":"if (env.Token.IsCancellationRequested) { /* abort before running the pipeline */ }","typeGuard":null,"tryCatchPattern":"try { var r = iterable.CountIO().Run(EnvIO.New(token)); }\ncatch (OperationCanceledException) { /* handle cancellation */ }","preventionTips":["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"],"tags":["cancellation","ienumerable","languageext"],"backgroundTag":"operation-cancelled","analyzedSha":"2f0e3628242889774d4141960a35671a0280051f","analyzedAt":"2026-09-15T03:31:55.716Z","contentChangedAt":"2026-09-15T03:31:55.716Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}