{"record":{"id":"5a81f34b70548924","repo":"louthy/language-ext","slug":"operationcanceledexception","errorCode":null,"errorMessage":"OperationCanceledException","messagePattern":"OperationCanceledException","errorType":"exception","errorClass":"OperationCanceledException","httpStatus":null,"severity":"info","filePath":"LanguageExt.Core/Effects/IO/Prelude/IO.Prelude.cs","lineNumber":30,"sourceCode":"\npublic static partial class Prelude\n{\n    /// <summary>\n    /// Access the cancellation-token from the IO environment\n    /// </summary>\n    /// <returns>CancellationToken</returns>\n    public static readonly IO<CancellationToken> cancelToken =\n        IO.lift(e => e.Token);\n\n    /// <summary>\n    /// Request a cancellation of the IO expression\n    /// </summary>\n    public static readonly IO<Unit> cancel =\n        IO.lift<Unit>(\n            e =>\n            {\n                e.Source.Cancel();\n                throw new OperationCanceledException();\n            });\n    \n    /// <summary>\n    /// Always yields a `Unit` value\n    /// </summary>\n    public static readonly IO<Unit> unitIO = \n        IO.pure<Unit>(default);\n    \n    /// <summary>\n    /// Yields the IO environment\n    /// </summary>\n    public static readonly IO<EnvIO> envIO = \n        IO.lift<EnvIO>(e => e);\n\n    /// <summary>\n    /// Tail call \n    /// </summary>\n    /// <param name=\"tailIO\"></param>","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/louthy/language-ext/blob/2f0e3628242889774d4141960a35671a0280051f/LanguageExt.Core/Effects/IO/Prelude/IO.Prelude.cs#L12-L48","documentation":"IO.cancel (IO.Prelude) is an IO<Unit> that cancels the ambient CancellationTokenSource and then throws OperationCanceledException. It is the library's intended way to abort an IO computation; the exception is the cancellation signal, not a bug.","triggerScenarios":"Evaluating the `cancel` IO value, directly or as part of a larger IO chain (e.g. io.Bind(_ => IO.cancel)), which calls e.Source.Cancel() and throws OperationCanceledException.","commonSituations":"Deliberately aborting long-running IO flows, wiring a cancellation branch into a selective/awaitAny-style composition, or accidentally including `cancel` in a pipeline that then unwinds.","solutions":["If cancellation is intended, catch OperationCanceledException (or use IO.Catch with a cancellation filter) at the top of the flow","Check Token.IsCancellationRequested via the IO environment instead of hard-throwing when you want graceful shutdown","Ensure bracket/finalizer logic (Bracket/BracketFail) is used so resources are released on cancellation","Do not swallow OperationCanceledException generically with catch(Exception); rethrow or filter it"],"exampleFix":"// before\nvar io = work.Bind(_ => IO.cancel); // unwinds with OperationCanceledException\n// after\nvar io = work.Bind(_ => IO.cancel).Catch(OperationCanceledException (_)=> IO.unit); // or handle at boundary","handlingStrategy":"try-catch","validationCode":"// No pre-check possible: evaluating IO.cancel always throws; branch conditionally instead\nif (shouldStop) { /* choose a non-throwing IO path */ }","typeGuard":"bool IsCancelled(Exception e) => e is OperationCanceledException;","tryCatchPattern":"try { result = io.Run(env); }\ncatch (OperationCanceledException) { /* expected cancellation path */ }","preventionTips":["Use IO.cancel deliberately and document it at the composition boundary","Never catch bare Exception in ways that swallow OperationCanceledException","Use Bracket so finalizers run on cancellation","Prefer token-based checks for graceful shutdown instead of hard throws"],"tags":["cancellation","io","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"}