Repository navigation
VerificationException on runtime, due to upcast to obj inside the task state machine #16154
Description
Activity
- changed the title
[-]VerificationException on runtime due to upcast of inside task state machine[/-][+]VerificationException on runtime, due to upcast to obj inside the task state machine[/+]on Oct 22, 2023 - addedArea-Compiler-StateMachinesSequence, list, task and other state machine compilationSequence, list, task and other state machine compilationImpact-Low(Internal MS Team use only) Describes an issue with limited impact on existing code.(Internal MS Team use only) Describes an issue with limited impact on existing code.and removed
on Oct 23, 2023 (to be verified if/since-when this is a regression)
github-actions commented
on Mar 28, 2026 on Mar 28, 2026 – with GitHub ActionsContributorMore actions🤖 This is an automated response from Repo Assist.
I tested this with the current compiler (F# Interactive version 15.2.100.0 for F# 11.0, commit
a0cce49, .NET 10.0.5 on Linux):$ echo '#version;;' | fsi Microsoft (R) F# Interactive version 15.2.100.0 for F# 11.0 Language Version: 10.0 FSharp.Core: 11.0.0.0 .NET: .NET 10.0.5The repro code compiles and runs correctly:
open System.Linq type Shape = {x: int; y: int} let returnFilter condition = task { if condition = "a" then let filter1 : IQueryable<Shape> -> IQueryable<Shape> = fun data -> data.Where(fun a -> a.x = 1) return Some filter1 elif condition = "b" then let filter2 : IQueryable<Shape> -> IQueryable<Shape> = fun data -> data.Where(fun a -> a.y <> 2) return Some filter2 else return None } let data = [{x = 1; y = 1}; {x = 2; y = 2}].AsQueryable() let result = task { let! f1 = returnFilter "a" let! f2 = returnFilter "b" match f1, f2 with | Some filter1, Some filter2 -> return data |> filter2 |> filter1 |> Seq.toList | _ -> return [] } |> (fun t -> t.GetAwaiter().GetResult()) // Result: [{ x = 1; y = 1 }] ✅
The
returnFilterfunction is now correctly inferred asstring -> Task<(IQueryable<Shape> -> IQueryable<Shape>) option>(no longer#IQueryable), and noVerificationExceptionis thrown at runtime. The task filter composition works correctly, returning the expected filtered result.Generated by Repo Assist · ◷
To install this agentic workflow, run
gh aw add githubnext/agentics/workflows/repo-assist.md@9135cdfde26838a01779aa966628308404ec1f02- added a commit that references this issue
on Mar 31, 2026 github-actions commented
on Mar 31, 2026 on Mar 31, 2026 – with GitHub ActionsContributorMore actions🤖 Issue still reproduces. Regression test in #19530 (PR) confirms it on Desktop .NET Framework. Still errors with:
VerificationException: type argument 'System.Object' violates the constraint of type parameter 'a'. Apologies for the incorrect label.Generated by Regression PR Shepherd · ◷
- added a commit that references this issue
on Apr 10, 2026 This now only happens in .NET Framework due to stricter IL verification. NET10 passes.
- added a commit that references this issue
on May 7, 2026
There I was, minding my own business, of writing generic higher order functions in asynchronous code, when she hit me, the task-state-machine. She has hit me before, but this time I think she left some traces of her, so I could saw a glimpse of that monster. So I'll report it here, even this will probably be closed "as designed", it might help some other guy struggling in seduction by her.
I haven't been able to repro it in short code, yet, but this is what is going on.
Observe the following code:
...and then composing these filters back and forth, e.g.
Expected behavior
Silly me, by the code I expected the type of
returnFilteris:string -> Task<(IQueryable<Shape> -> IQueryable<Shape>) option>Actual behavior
Well, the actual type of
returnFilteris:string -> Task<(#IQueryable<Shape> -> IQueryable<Shape>) option>The code compiled well.
But this hash # made all the difference, because combining different returnFilters together caused them to be automatically upcasted to
obj.Thus the code threw at runtime:
What I historically do is change the code from
tasktoasyncand all is good, but not this time:Known workarounds
Do write the parameters explicitly.
You can even declare a type for your function:
Related information
Provide any related information (optional):