Skip to content

Using FrozenSet.Contains and enums throws ArgumentNullException: Value cannot be null (Parameter 'constructor') #3385

Closed

Description

@SapiensAnatis

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

  1. added a commit that references this issue on Nov 24, 2024
  2. roji commented on Nov 28, 2024

    @roji
    Member

    Closing as a duplicate of dotnet/efcore#35102 on the EF side.

  3. cincuranet commented on Nov 29, 2024

    @cincuranet

    @roji This seems to be different issue. Using FrozenSet in dotnet/efcore#35102 repro works just fine. Based on the stack, this looks more like an issue in provider, because it happens later (in NpgsqlArrayConverter) in the pipeline compared to dotnet/efcore#35102.

  4. roji commented on Nov 30, 2024

    @roji
    Member

    OK, thanks for checking! Will look on my side.

  5. reopened this on Nov 30, 2024
  6. WhatzGames commented on Dec 15, 2024

    @WhatzGames
    Contributor

    @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.

  7. added theissue type on Jun 14, 2025
  8. roji commented on Oct 18, 2026

    @roji
    Member

    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

    Provider Provider version EF Core version Result
    Npgsql 8.0.10 8.0.10 Succeeds
    Npgsql 9.0.0 9.0.0 Reported ArgumentNullException (constructor)
    Npgsql 9.0.1 9.0.0 Same exception
    Npgsql 9.0.4 9.0.4 Same exception
    Npgsql 9.0.4 9.0.21 Same exception
    Npgsql 10.0.0 10.0.0 Succeeds
    Npgsql 10.0.3 10.0.4 Succeeds
    SQLite 9.0.0 9.0.0 Succeeds

    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 with ToQueryString(), 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 to Expression.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

    • dotnet/efcore#35102 is not a duplicate: it concerns an ImmutableArray/AsQueryable expression-type mismatch during query normalization, not Npgsql array-converter construction.
    • dotnet/efcore#36496 is related by collection type, but its eventual repro uses a static readonly 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:

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.1" />
        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
      </ItemGroup>
    </Project>

    Program.cs:

    using System.Collections.Frozen;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.Logging;
    
    await using var context = new BlogContext();
    
    var tags = new[] { TagValue.Gaming, TagValue.Recipe }.ToFrozenSet();
    
    _ = context.Tags.Where(t => tags.Contains(t.Value)).ToQueryString();
    
    public class BlogContext : DbContext
    {
        public DbSet<Tag> Tags { get; set; }
    
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            => optionsBuilder
                .UseNpgsql("Host=localhost;Database=repro")
                .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
    }

    Run with dotnet run. To check the SQLite control, replace the provider package with Microsoft.EntityFrameworkCore.Sqlite 9.0.0 and UseNpgsql(...) with UseSqlite("Data Source=:memory:").

  9. roji commented on Oct 18, 2026

    @roji
    Member

    Closing as this was already fixed in 10.0.

  10. added this to the 10.0.4 milestone on Oct 18, 2026
  11. modified the milestones: 10.0.4, 10.0.0 on Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions