Skip to content

ObjectDisposedException in ManualResetEventSlim.Reset() during runtime queries (latency-dependent race condition) #6415

@fthsrlk

Description

@fthsrlk

ObjectDisposedException in ManualResetEventSlim during runtime queries (latency-dependent race condition)

Environment

  • Npgsql Version: 10.0.1
  • .NET Version: 10.0
  • PostgreSQL: Supabase (via pooler.supabase.com - PgBouncer Transaction Mode)
  • OS: Windows 11

Description

We are experiencing ObjectDisposedException on ManualResetEventSlim.Reset() in NpgsqlConnector.ResetCancellation() during runtime database queries.

Critical finding: The error is latency-dependent and 100% reproducible:

  • Low latency (5-20ms): Never fails (Azure EU → Supabase EU)
  • High latency (100-300ms): Always fails (Turkey → Supabase EU)

This suggests a race condition where the timing window is only hit under high-latency conditions.

Stack Trace

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Threading.ManualResetEventSlim'.
   at System.Threading.ManualResetEventSlim.Reset()
   at Npgsql.Internal.NpgsqlConnector.ResetCancellation()
   at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)

Minimal Reproduction (without EF Core)

using Npgsql;

// Connection to Supabase via PgBouncer Transaction Mode pooler
var connectionString = "Host=aws-0-eu-central-1.pooler.supabase.com;Database=postgres;Username=postgres.xxx;Password=xxx;Port=5432;SSL Mode=Require;Multiplexing=false";

// Simulate high-latency environment or run from location with >100ms latency to database
await using var conn = new NpgsqlConnection(connectionString);
await conn.OpenAsync();

// Run multiple parallel queries to increase race condition probability
var tasks = Enumerable.Range(0, 10).Select(async _ =>
{
    await using var cmd = new NpgsqlCommand("SELECT 1", conn);
    await cmd.ExecuteScalarAsync();
});

await Task.WhenAll(tasks); // ObjectDisposedException occurs here under high latency

Frequency

  • Every query under high-latency conditions (100-300ms)
  • Never under low-latency conditions (5-20ms)
  • Deterministic, not random

Connection Details

  • Supabase Pooler: PgBouncer in Transaction Mode (pooler.supabase.com)
  • Multiplexing: Disabled (Multiplexing=false)
  • SSL: Required

Attempted Workarounds (None Worked)

Configuration Result
Pooling=false Still fails
NoResetOnClose=true Still fails
CancellationTimeout=0 Still fails
Multiplexing=false Still fails
Upgrade 10.0.0 → 10.0.1 Still fails

Analysis

The error occurs in ResetCancellation() which calls ManualResetEventSlim.Reset(). Under high latency:

  1. Query execution takes longer due to network delay
  2. This appears to trigger Npgsql's internal cancellation/timeout mechanism
  3. A race condition occurs: one thread disposes ManualResetEventSlim while another calls Reset()

The latency dependency explains why:

  • Production (low latency) never hits the timing window
  • Remote development (high latency) consistently hits it

Related Issues

Additional Context

This issue affects all runtime queries, not just EF Core migrations. The EF Core issue #3699 specifically states "non-design time activities function" - our finding expands the scope significantly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions