Repository navigation
Using FrozenSet.Contains and enums throws ArgumentNullException: Value cannot be null (Parameter 'constructor') #3385
Description
Hey, I was upgrading to .NET 9 and as part of that went from Npgsql.EntityFrameworkCore.PostgreSQL 8.0.10 to 9.0.1, and Microsoft.EntityFrameworkCore 8.0.10 to 9.0.0. I found that some previously-working code that used FrozenSet.Contains in a Where call no longer worked, and now throws an ArgumentNullException which appears to be inside Npgsql. (The stack trace is the only reason I'm opening an issue here and not in dotnet/efcore, let me know if I'm wrong!)
Here's a minimal repro:
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
await using var context = new BlogContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
FrozenSet<TagValue> tags = [TagValue.Gaming, TagValue.Recipe];
// List<TagValue> tags = [TagValue.Gaming, TagValue.Recipe]; // this works
var existingEntities = await context
.Tags.Where(t => tags.Contains(t.Value))
.ToListAsync();
public class BlogContext : DbContext
{
public DbSet<Tag> Tags { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseNpgsql("Host=localhost;User ID=postgres;Password=Abcd5678;Database=test")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
}
public class Tag
{
public int Id { get; set; }
public TagValue Value { get; set; }
}
public enum TagValue
{
Recipe,
Politics,
Gaming
}On version 9.0.2-ci.20241120T194418 this throws the following exception for me:
Unhandled exception. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.ArgumentNullException: Value cannot be null. (Parameter 'constructor')
at System.ArgumentNullException.Throw(String paramName)
at System.ArgumentNullException.ThrowIfNull(Object argument, String paramName)
at System.Linq.Expressions.Expression.New(ConstructorInfo constructor, IEnumerable`1 arguments)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.ValueConversion.NpgsqlArrayConverter`3.ArrayConversionExpression[TInput,TOutput,TConcreteOutput](LambdaExpression elementConversionExpression)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.ValueConversion.NpgsqlArrayConverter`3..ctor(ValueConverter elementConverter)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
--- End of inner exception stack trace ---
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture)
at System.Activator.CreateInstance(Type type, Object[] args)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping.NpgsqlArrayTypeMapping`3.CreateParameters(String storeType, RelationalTypeMapping elementMapping)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping.NpgsqlArrayTypeMapping`3..ctor(String storeType, RelationalTypeMapping elementTypeMapping)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping.NpgsqlArrayTypeMapping`3..ctor(RelationalTypeMapping elementTypeMapping)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
--- End of inner exception stack trace ---
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture)
at System.Activator.CreateInstance(Type type, Object[] args)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlTypeMappingSource.FindCollectionMapping(RelationalTypeMappingInfo info, Type modelType, Type providerType, CoreTypeMapping elementMapping)
at Microsoft.EntityFrameworkCore.Storage.RelationalTypeMappingSource.<>c.<FindMappingWithConversion>b__8_0(ValueTuple`4 k, RelationalTypeMappingSource self)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd[TArg](TKey key, Func`3 valueFactory, TArg factoryArgument)
at Microsoft.EntityFrameworkCore.Storage.RelationalTypeMappingSource.FindMappingWithConversion(RelationalTypeMappingInfo mappingInfo, Type providerClrType, ValueConverter customConverter)
at Microsoft.EntityFrameworkCore.Storage.RelationalTypeMappingSource.FindMapping(Type type, IModel model, CoreTypeMapping elementMapping)
at Npgsql.EntityFrameworkCore.PostgreSQL.Query.NpgsqlSqlExpressionFactory.ApplyTypeMappingsOnItemAndArray(SqlExpression itemExpression, SqlExpression arrayExpression)
at Npgsql.EntityFrameworkCore.PostgreSQL.Query.Internal.NpgsqlQueryableMethodTranslatingExpressionVisitor.TranslateContains(ShapedQueryExpression source, Expression item)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.TranslateSubquery(Expression expression)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.<VisitMethodCall>g__TranslateAsSubquery|33_0(Expression expression, <>c__DisplayClass33_0&)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Npgsql.EntityFrameworkCore.PostgreSQL.Query.Internal.NpgsqlSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateInternal(Expression expression, Boolean applyDefaultTypeMapping)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.Translate(Expression expression, Boolean applyDefaultTypeMapping)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateExpression(Expression expression, Boolean applyDefaultTypeMapping)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateLambdaExpression(ShapedQueryExpression shapedQueryExpression, LambdaExpression lambdaExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateWhere(ShapedQueryExpression source, LambdaExpression predicate)
at Npgsql.EntityFrameworkCore.PostgreSQL.Query.Internal.NpgsqlQueryableMethodTranslatingExpressionVisitor.TranslateWhere(ShapedQueryExpression source, LambdaExpression predicate)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutorExpression[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass11_0`1.<ExecuteCore>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteCore[TResult](Expression query, Boolean async, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Program.<Main>$(String[] args) in C:\Users\jay0\Projects\EFCoreIssue35102\EFCoreIssue35102\Program.cs:line 13
at Program.<Main>$(String[] args) in C:\Users\jay0\Projects\EFCoreIssue35102\EFCoreIssue35102\Program.cs:line 13
at Program.<Main>(String[] args)
(ignore the project name, this initially presented similar to a different issue I found and I based the minimal reproduction off of the one I found there)
Notably, if I change the FrozenSet<TagValue> to be a List<TagValue>, it works. I can also insert a call to AsEnumerable before the Contains, which also fixes the issue. It also appears to be specific to enums, if I make the tags a string then it works with FrozenSet<string>
Activity
Handle EF regression
roji commentedon Nov 28, 2024
Closing as a duplicate of dotnet/efcore#35102 on the EF side.
cincuranet commentedon Nov 29, 2024
@roji This seems to be different issue. Using
FrozenSetin dotnet/efcore#35102 repro works just fine. Based on the stack, this looks more like an issue in provider, because it happens later (inNpgsqlArrayConverter) in the pipeline compared to dotnet/efcore#35102.roji commentedon Nov 30, 2024
OK, thanks for checking! Will look on my side.
WhatzGames commentedon Dec 15, 2024
@roji I'm sorry, I should've probably notified you before I took the initiative to go on a hunt. I spent some time to fiddle around and at least when running the repro with my PR, it's no longer an issue.
roji commentedon Oct 18, 2026
AI Triage
The below is an AI-generated analysis and may contain inaccuracies.
Confirmed PostgreSQL-provider bug and regression from 8.x to 9.x. It is already fixed in 10.0.0. The issue has been classified as Bug.
Reproduction and version comparison
ArgumentNullException(constructor)The 8.x/9.x comparisons used the same .NET 8 runtime, isolating the package regression from the runtime upgrade; 10.x used .NET 10. The 8.x/9.x results were checked with
ToListAsync()against PostgreSQL 18.4, with SQLite as the other-provider control. The minimized program below reproduces the same failure withToQueryString(), so neither a running database nor seed data is needed. The 10.x results were checked with that minimized program.Cause and existing fix
The enum's numeric conversion causes Npgsql to create an array converter over the collection. That converter builds both conversion directions, including the unused database-to-
FrozenSet<TagValue>direction.FrozenSet<T>cannot be constructed with a public parameterless constructor, and the 9.x converter passes the missing constructor toExpression.New, producing the reported exception.#3629, which fixed #3050, already addresses this underlying problem by allowing one-directional collection conversions without requiring the unused reverse direction to be constructible. That change is included in 10.0.0. The older proposed fix in #3405 remains open, but is not needed to make this repro work in 10.x.
Related upstream issues
ImmutableArray/AsQueryableexpression-type mismatch during query normalization, not Npgsql array-converter construction.FrozenSet<string>and fails method translation. It does not match this captured enum-set constructor failure.Recommendation: Close as fixed by #3629, unless a 9.x backport is intended. Updating EF Core alone within 9.x does not fix it.
minimal repro
Repro.csproj:Program.cs:Run with
dotnet run. To check the SQLite control, replace the provider package withMicrosoft.EntityFrameworkCore.Sqlite9.0.0 andUseNpgsql(...)withUseSqlite("Data Source=:memory:").roji commentedon Oct 18, 2026
Closing as this was already fixed in 10.0.