dotnet/efcore · error · InvalidOperationException

A synchronous store management operation was performed and…

Error message

A synchronous store management operation was performed and no synchronous seed delegate has been provided, however an asynchronous seed delegate was. Set 'UseSeeding' option with a delegate equivalent to the one supplied in 'UseAsyncSeeding'.

What it means

The synchronous Migrator path ran a store-management/migration operation. The configured DbContextOptions has an async seeder (UseAsyncSeeding) but no synchronous seeder (UseSeeding), so the sync path has nothing to call. EF requires the two delegates to be supplied as a matching pair so sync and async execution are both covered.

Solutions

  1. Add optionsBuilder.UseSeeding((ctx, anyOp) => { ... }) with a sync equivalent of your async seeder.
  2. Keep UseSeeding and UseAsyncSeeding logic in sync (call the same helper from both).
  3. If the operation must be async-only, switch the caller to the async API (MigrateAsync) so the sync path is never reached.

Example fix

// before
options.UseSqlServer(conn)
       .UseAsyncSeeding(async (ctx, anyOp, ct) =>
       {
           await ctx.Products.AddAsync(new Product { Id = 1 }, ct);
           await ctx.SaveChangesAsync(ct);
       });

// after
options.UseSqlServer(conn)
       .UseSeeding((ctx, anyOp) =>
       {
           ctx.Products.Add(new Product { Id = 1 });
           ctx.SaveChanges();
       })
       .UseAsyncSeeding(async (ctx, anyOp, ct) =>
       {
           await ctx.Products.AddAsync(new Product { Id = 1 }, ct);
           await ctx.SaveChangesAsync(ct);
       });
Defensive patterns

Strategy: validation

Validate before calling

// At startup, assert the seeder pair is configured together
static void EnsureSeederPair(DbContextOptions opts)
{
    var ext = opts.FindExtension<CoreOptionsExtension>();
    if ((ext?.Seeder == null) ^ (ext?.AsyncSeeder == null))
        throw new InvalidOperationException(
            "Configure both UseSeeding and UseAsyncSeeding together.");
}

Prevention

When it happens

Trigger: optionsBuilder.UseAsyncSeeding(...) was called without a matching UseSeeding(...), and a synchronous migration API is invoked (e.g. context.Database.Migrate(), Database.EnsureCreated(), or Migrator.Migrate on a sync code path).

Common situations: App configured only async seeding because the rest of the app is async, but a sync startup or test harness calls EnsureCreated/Migrate; upgrading from an older EF version that had a single seeding hook; copy-paste that lost the UseSeeding call.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/0cc1dba5d1b3a284. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Migrations/Internal/Migrator.cs:203

                    getCommands(), _connection, state, commitTransaction: useTransaction, MigrationTransactionIsolationLevel);
            }

            var coreOptionsExtension =
                _contextOptions.FindExtension<CoreOptionsExtension>()
                ?? new CoreOptionsExtension();

            var seed = coreOptionsExtension.Seeder;
            if (seed != null)
            {
                if (!state.SeedingCompleted)
                {
                    seed(context, state.AnyOperationPerformed);
                    state.SeedingCompleted = true;
                }
            }
            else if (coreOptionsExtension.AsyncSeeder != null)
            {
                throw new InvalidOperationException(CoreStrings.MissingSeeder);
            }

            state.Transaction?.Commit();
            return state.AnyOperationPerformed;
        }
        finally
        {
            state.DatabaseLock?.Dispose();
            state.DatabaseLock = null;
            state.Transaction?.Dispose();
            state.Transaction = null;
            _connection.Close();
        }
    }

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in

View on GitHub (pinned to 3a2006ef56)