{"record":{"id":"23e61ac947ce6b10","repo":"dotnet/efcore","slug":"user-transaction-is-not-supported-with-a-transacti-23e61a","errorCode":null,"errorMessage":"User transaction is not supported with a TransactionSuppressed migrations or a retrying execution strategy.","messagePattern":"User transaction is not supported with a TransactionSuppressed migrations or a retrying execution strategy\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Migrations/Internal/Migrator.cs","lineNumber":374,"sourceCode":"            state.DatabaseLock?.Dispose();\n            state.DatabaseLock = null;\n\n            if (state.Transaction != null)\n            {\n                await state.Transaction.DisposeAsync().ConfigureAwait(false);\n                state.Transaction = null;\n            }\n\n            await _connection.CloseAsync().ConfigureAwait(false);\n        }\n    }\n\n    private void ValidateMigrations(bool useTransaction, string? targetMigration)\n    {\n        if (!useTransaction\n            && _executionStrategy.RetriesOnFailure)\n        {\n            throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction);\n        }\n\n        if (_migrationsAssembly.Migrations.Count == 0)\n        {\n            _logger.MigrationsNotFound(this, _migrationsAssembly);\n        }\n        else if (_migrationsAssembly.ModelSnapshot == null)\n        {\n            _logger.ModelSnapshotNotFound(this, _migrationsAssembly);\n        }\n        else if (targetMigration == null\n                 && RelationalResources.LogPendingModelChanges(_logger).WarningBehavior != WarningBehavior.Ignore\n                 && HasPendingModelChanges())\n        {\n            var modelSource = (ModelSource)_currentContext.Context.GetService<IModelSource>();\n#pragma warning disable EF1001 // Internal EF Core API usage.\n            var newDesignTimeModel = modelSource.CreateModel(\n                _currentContext.Context, _currentContext.Context.GetService<ModelCreationDependencies>(), designTime: true);","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Migrations/Internal/Migrator.cs#L356-L392","documentation":"ValidateMigrations throws when the caller asked to run migrations without an explicit transaction (useTransaction == false, i.e. a 'transaction-suppressed' migration) AND the configured execution strategy retries on failure. Retrying individual commands outside a transaction can leave the database half-migrated, so EF refuses the unsafe combination rather than risk inconsistency.","triggerScenarios":"Migrator.Migrate/MigrateAsync is invoked with useTransaction:false (or via a context configured with TransactionSuppressed behavior) while options.UseSqlServer(...).UseExecutionStrategy(s => new SqlServerRetryingExecutionStrategy(s)) or any strategy whose RetriesOnFailure is true is registered.","commonSituations":"Enabling retry-on-failure for Azure SQL then trying to run migrations outside a transaction to work around a long-running DDL statement; mixing EnableRetryOnFailure with a custom Migrate call that passes useTransaction:false; legacy migration runner that suppressed transactions.","solutions":["Run the migration inside a transaction (default) — remove the useTransaction:false / suppression.","If you must suppress transactions, switch to a non-retrying execution strategy (the default ExecutionStrategy) for migrations.","For one-off long DDL, split it into smaller migrations that fit in a transaction instead of suppressing."],"exampleFix":"// before\noptions.UseSqlServer(conn)\n       .EnableRetryOnFailure();            // retrying strategy\nawait db.Database.MigrateAsync(cancellationToken); // fine\n// but somewhere: migrator.Migrate(useTransaction: false)  -> throws\n\n// after — keep transactions on with retries\nawait db.Database.MigrateAsync(cancellationToken);\n// or, if you truly need no transaction, drop retries for this run:\noptions.UseSqlServer(conn); // default, non-retrying strategy","handlingStrategy":"validation","validationCode":"// Before migrating, detect the unsafe combination\nstatic bool IsRetrying(DbContext db)\n    => db.GetService<IExecutionStrategy>() is { RetriesOnFailure: true };\n\nif (IsRetrying(db) && suppressTransaction)\n    throw new InvalidOperationException(\n        \"Retrying strategy cannot run with transaction suppression.\");","typeGuard":"null","tryCatchPattern":null,"preventionTips":["Do not combine EnableRetryOnFailure with transaction-suppressed migrations.","Keep retry strategies for runtime CRUD, not for DDL-heavy migrations, or accept transactions.","Document the migration transaction policy in the project's runbook."],"tags":["migrations","transactions","execution-strategy","configuration"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}