You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
10.x: RangeSet.Contains throws ArgumentException on the EF Core 10 patch that carries dotnet/efcore#37081 #288
dotnet/efcore#39114 ("[release/10.0] Fix Contains handling for read-only collections") merged into release/10.0 on 2026-10-02 and is not in EF Core 10.0.13, the newest patch as of 2026-10-19. The patch that carries it makes EF Core 10 normalize every Contains on an IReadOnlyCollection<T> into Queryable.Contains over the element type, which is TRange for a RangeSet<TRange, T>. On that patch every RangeSet.Contains(T) and Contains(RangeSet) in a query throws ArgumentException inside EF Core, before any translator runs — the failure the 11 line hit on EF Core 11 RC1 (see the 11.0.0 issue, fixed on main by the #103 PR).
The repository's own test runs pin EF Core 10.0.0 through Npgsql 10.0.0's floor, so CI on release/10.x does not see it; a consumer on the newer patch does. Loud, not silent.
Change
Cherry-pick the main fix (RangeSetContains, the interceptor rewrite and the translator case) with -x into a PR against release/10.x, and make the EF Core translation tests run on the patch that carries the change once it is published, so the line's CI sees what its consumers see.
Done when
Measurable now, without waiting for EF Core 10.0.15: on release/10.x the interceptor rewrites all three RangeSet.Contains overloads onto RangeSetContains, a translation test asserts that no instance Contains call whose declaring type implements IReadOnlyCollection<> survives interception (BCL and NodaTime range sets alike), the @> SQL of every existing RangeSet.Contains test is unchanged, and reverting the rewrite fails that test while the SQL tests still pass — which is why the defect was invisible. Ships in 10.1.0 (a minor; the fix is loud, the minor is for #300).
Re-check, not a gate: when EF Core 10.0.15 is published, run the EF suites on it through the #297 leg (or the scratch float described there) and record the result in a comment here.
Root cause: EF Core's Contains normalization, exposed by RangeSet being a collection
The defect is in EF Core. QueryableMethodNormalizingExpressionVisitor rewrites a call into Queryable.Contains when the method is namedContains, its declaring type is generic, and that type implements ICollection<> — and, since dotnet/efcore#37390 (backported to release/10.0 as dotnet/efcore#39114, issue dotnet/efcore#37081), also IReadOnlyCollection<>. TryConvertCollectionContainsToQueryableContains then builds:
Two things are wrong with it, independent of this package:
It never checks the method is the collection's Contains(TElement). Any one-argument overload named Contains is rewritten, so an operand that is not the element type fails in Expression.Call with ArgumentException. That is RangeSet<TRange, T>.Contains(T) and Contains(RangeSet).
It takes the element type as the declaring type's first type argument, not the element type TryGetElementType found. For RangeSet<TRange, T> that guess happens to be right; for Foo<TKey, TItem> : ICollection<TItem> it is not.
Both already reproduce on EF Core 10.0.13 through ICollection<> (a scratch repro with a generic ICollection<Span> that has a Contains(int) overload, and a Keyed<TKey, TItem> : ICollection<TItem>; both throw from TryConvertCollectionContainsToQueryableContains). The patch adds no new defect; it widens the existing one to IReadOnlyCollection<>, which is where RangeSet sits (IReadOnlyList<TRange>). EF Core main (the 11 line) has the same code. An upstream report is being drafted.
What this package contributes is the exposure: RangeSet is a read-only list of its ranges whose Contains overloads take operands that are not ranges. The same reason value sets never implement IEnumerable<T>.
Consequences for this issue
The plan stands: the main fix moves the call onto a declaring type that is not a collection (RangeSetContains), which EF Core's check does not match, and it keeps working whether or not EF Core narrows the check later.
Stopgap for consumers on the patch before 10.x ships the fix: the backport carries an off switch.
It restores the pre-patch normalization (only ICollection<>), so RangeSet.Contains translates again; the cost is losing EF Core's own fix, so a captured IReadOnlySet<T> inlines its values instead of going out as one collection parameter. Worth a line in the 10.x changelog entry for this fix.
Filed upstream as dotnet/efcore#39329. The fix here doesn't wait on it: RangeSetContains takes the call off a collection's declaring type, so it holds whether or not EF Core narrows the check.
Npgsql EF 10.0.3, the newest provider patch, requires Microsoft.EntityFrameworkCore [10.0.4, 11.0.0), so every consumer on a current Npgsql EF already resolves an EF Core patch above the floor this repository tests on. When 10.0.15 ships, a plain dotnet restore with floating patch versions, or a Dependabot bump, is enough to hit this.
Port against release/10.x is #310 (branch fix/288-rangeset-contains-ef-core-patches, one hand-extracted commit naming PR #292). Since no published EF Core 10 patch carries dotnet/efcore#39114 yet and the dnceng dotnet10 feed lists no 10.0.x servicing build (its Microsoft.EntityFrameworkCore listing ends at 10.0.0-rtm.25513.102), the PR proves the fix on the query tree: a translation test per overload, on the BCL and NodaTime range sets, asserts no instance Contains on an IReadOnlyCollection<> survives interception, and fails with the rewrite stripped while every @> SQL test passes. Closed by hand after the merge.
Fixed on release/10.x by PR #310 (merge commit 9e4cce4, 2026-10-19): the interceptor moves the three RangeSet.Contains overloads onto RangeSetContains, proved through the interception tree since no published EF Core 10 patch carries dotnet/efcore#39114 yet. Re-check against EF Core 10.0.15 when it ships (#297's leg). Closed by hand: Closes acts only on main, where the fix arrived with PR #292 (#287).
Activity
CaffeinatedCoder commentedon Oct 19, 2026
Root cause: EF Core's
Containsnormalization, exposed byRangeSetbeing a collectionThe defect is in EF Core.
QueryableMethodNormalizingExpressionVisitorrewrites a call intoQueryable.Containswhen the method is namedContains, its declaring type is generic, and that type implementsICollection<>— and, since dotnet/efcore#37390 (backported torelease/10.0as dotnet/efcore#39114, issue dotnet/efcore#37081), alsoIReadOnlyCollection<>.TryConvertCollectionContainsToQueryableContainsthen builds:Two things are wrong with it, independent of this package:
Contains(TElement). Any one-argument overload namedContainsis rewritten, so an operand that is not the element type fails inExpression.CallwithArgumentException. That isRangeSet<TRange, T>.Contains(T)andContains(RangeSet).TryGetElementTypefound. ForRangeSet<TRange, T>that guess happens to be right; forFoo<TKey, TItem> : ICollection<TItem>it is not.Both already reproduce on EF Core 10.0.13 through
ICollection<>(a scratch repro with a genericICollection<Span>that has aContains(int)overload, and aKeyed<TKey, TItem> : ICollection<TItem>; both throw fromTryConvertCollectionContainsToQueryableContains). The patch adds no new defect; it widens the existing one toIReadOnlyCollection<>, which is whereRangeSetsits (IReadOnlyList<TRange>). EF Coremain(the 11 line) has the same code. An upstream report is being drafted.What this package contributes is the exposure:
RangeSetis a read-only list of its ranges whoseContainsoverloads take operands that are not ranges. The same reason value sets never implementIEnumerable<T>.Consequences for this issue
mainfix moves the call onto a declaring type that is not a collection (RangeSetContains), which EF Core's check does not match, and it keeps working whether or not EF Core narrows the check later.ICollection<>), soRangeSet.Containstranslates again; the cost is losing EF Core's own fix, so a capturedIReadOnlySet<T>inlines its values instead of going out as one collection parameter. Worth a line in the 10.x changelog entry for this fix.CaffeinatedCoder commentedon Oct 19, 2026
Filed upstream as dotnet/efcore#39329. The fix here doesn't wait on it:
RangeSetContainstakes the call off a collection's declaring type, so it holds whether or not EF Core narrows the check.CaffeinatedCoder commentedon Oct 19, 2026
Measured 2026-10-19 from the upstream PR and the published packages:
Microsoft.EntityFrameworkCore.Issue37081is in none of 10.0.0 through 10.0.13.Microsoft.EntityFrameworkCore [10.0.4, 11.0.0), so every consumer on a current Npgsql EF already resolves an EF Core patch above the floor this repository tests on. When 10.0.15 ships, a plaindotnet restorewith floating patch versions, or a Dependabot bump, is enough to hit this.mainfix lives in PR build: retarget main to .NET 11 for 11.0.0-preview.1 #292 (231f23a), which is a single commit holding the whole .NET 11 retarget, so the 10.x port is a hand-extracted commit that names the PR, not acherry-pick -xof it, unless build: retarget main to .NET 11 for 11.0.0-preview.1 #292 is split before merge.CaffeinatedCoder commentedon Oct 19, 2026
Port against
release/10.xis #310 (branchfix/288-rangeset-contains-ef-core-patches, one hand-extracted commit naming PR #292). Since no published EF Core 10 patch carries dotnet/efcore#39114 yet and the dncengdotnet10feed lists no 10.0.x servicing build (itsMicrosoft.EntityFrameworkCorelisting ends at10.0.0-rtm.25513.102), the PR proves the fix on the query tree: a translation test per overload, on the BCL and NodaTime range sets, asserts no instanceContainson anIReadOnlyCollection<>survives interception, and fails with the rewrite stripped while every@>SQL test passes. Closed by hand after the merge.fix: keep RangeSet.Contains out of EF Core's rewrite of Contains on a…
CaffeinatedCoder commentedon Oct 19, 2026
Fixed on
release/10.xby PR #310 (merge commit 9e4cce4, 2026-10-19): the interceptor moves the threeRangeSet.Containsoverloads ontoRangeSetContains, proved through the interception tree since no published EF Core 10 patch carries dotnet/efcore#39114 yet. Re-check against EF Core 10.0.15 when it ships (#297's leg). Closed by hand:Closesacts only onmain, where the fix arrived with PR #292 (#287).