F# 5.0 async block default cancellation token behavior shift in .NET 5+
0 reputation · 14 Feb 2026, 08:47 UTC
Goal: Migrate an F# codebase using async { } blocks to .NET 5+ while preserving existing cancellation semantics without introducing unexpected blocking or token propagation behavior.
Constraint: F# 5.0 altered the default cancellation token handling for async blocks, changing how the runtime supplies or expects a token during execution. Code that previously relied on the prior default may now encounter cooperative cancellation surprises, especially when async workflows interoperate with .NET ThreadPool tasks or external cancellation sources.
Uncertainty: Whether the runtime automatically injects a CancellationToken.None or a derived token into async { } blocks on .NET 5+, and how that affects workflows that do not explicitly pass a token. The precise boundary between implicit and explicit token propagation remains ambiguous for mixed-version or library-level code.
Does the .NET 5 runtime supply a default cancellation token to async { } blocks that omit an explicit token argument? How does this default interact with cancellation tokens passed to Async.Start or Async.RunSynchronously? What migration strategy preserves original cancellation semantics across F# 4.x and F# 5+ runtimes?