Skip to content

Unexpected 'database is locked' error. #36295

Closed

Description

@stefanpavlov

Bug description

I'm getting SQLite Error 5: 'database is locked' exceptions when multiple parallel requests delete different rows of a table. The database connection is configured with a 1 day command timeout and for most of the requests this works fine and the request takes either a couple of milliseconds if the database is not in use or some amount of time if it is. See logs:

Log of successful commands

info: EfCoreSqliteDatabaseLockedRepro[0]
File e2cfbaed-0a49-49bf-9f6e-b2f2bba0ac23 deleted in 191 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File f577ff72-8e63-4825-b244-0a567d36b791 deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File bba72f07-51fe-493a-984e-3cdff9dc0657 deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File bcbd877d-2749-4c5c-be25-6890a2660e13 deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 3b307cc2-a93b-4737-80ab-d21509efcfe3 deleted in 3 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 88d8cf6e-03ec-4fa9-b7d0-e0707b51de4d deleted in 3 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 26dea114-427b-4c80-a58d-20a48ccc20a7 deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 9b5f24d3-76d4-4248-8aa6-133235ae1565 deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 21d6fff2-322b-43b6-892c-dc36fc52a600 deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File e7706c4d-5477-41e7-bcfa-240802eed4dd deleted in 3 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File a66d0ae6-e916-4b2c-822b-8d6285e74124 deleted in 3 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 6f4f1566-b771-45f2-ac96-22b4e5c9e49e deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 9f50b5a0-ea20-42d7-82c8-64c36311737d deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 36fa19ef-c311-4f85-8f07-6cfd8eb2cad2 deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File c7ddb41d-affa-4a72-8adb-8195fe69a0cb deleted in 3 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 868acee7-2040-4d38-b0b3-cab8c898563d deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 4eeac983-7265-405b-b829-15e677b9d8a1 deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 5531983c-c75b-467c-a8cd-ea72810112bd deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 0e05f8f3-27ca-4265-84b4-082ec83d4c91 deleted in 2 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 72ce4c17-69a1-4b40-bb63-3b6b7d456c68 deleted in 659 ms
info: EfCoreSqliteDatabaseLockedRepro[0]
File 3525c6d0-8c2e-434b-9227-c5c54bcd1ec3 deleted in 3 ms

A small percent of requests, however, fail with database is locked error:

Log of failed commands

fail: EfCoreSqliteDatabaseLockedRepro[0]
Failed to delete file 19b70b8d-3d21-42e4-a4b3-7afea35d5a97 in 1256 ms
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'.
at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
at Microsoft.Data.Sqlite.SqliteDataRecord.Dispose()
at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
at System.Data.Common.DbDataReader.NextResultAsync(CancellationToken cancellationToken)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList1 entries, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Program.<>c__DisplayClass0_0.<<

$>b__3>d.MoveNext() in C:\dev\personal\dotnet-playground\EfCoreSqliteDatabaseLockedRepro\Source\Program.cs:line 53

...

fail: EfCoreSqliteDatabaseLockedRepro[0]
Failed to delete file e6e39f29-df22-4500-aa7b-56bf1e59f0c0 in 7 ms
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'.
at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
at Microsoft.Data.Sqlite.SqliteDataRecord.Dispose()
at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
at System.Data.Common.DbDataReader.NextResultAsync(CancellationToken cancellationToken)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList1 entries, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Program.<>c__DisplayClass0_0.<<

$>b__3>d.MoveNext() in C:\dev\personal\dotnet-playground\EfCoreSqliteDatabaseLockedRepro\Source\Program.cs:line 53

I must be doing something wrong but I can't for the life of me figure it out.
Any help fixing this problem will be greatly appreciated.

Your code

https://github.com/stefanpavlov/EfSqliteDatabaseLockedMinRepro

Stack traces

fail: Microsoft.EntityFrameworkCore.Update[10000]
      An exception occurred in the database while saving changes for context type 'ApplicationDbContext'.
      Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
       ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'.
         at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
         at Microsoft.Data.Sqlite.SqliteDataRecord.Dispose()
         at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
         at System.Data.Common.DbDataReader.NextResultAsync(CancellationToken cancellationToken)
      --- End of stack trace from previous location ---
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         --- End of inner exception stack trace ---
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
      Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
       ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'.
         at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
         at Microsoft.Data.Sqlite.SqliteDataRecord.Dispose()
         at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
         at System.Data.Common.DbDataReader.NextResultAsync(CancellationToken cancellationToken)
      --- End of stack trace from previous location ---
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         --- End of inner exception stack trace ---
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)

Verbose output


EF Core version

9,0,6

Database provider

Assembly Microsoft.EntityFrameworkCore.Sqlite

Target framework

.NET 9

Operating system

Windows 11

IDE

Visual Studio 2022 17.14.7

Activity

  1. stefanpavlov commented on Jul 7, 2025

    @stefanpavlov
    Author

    Any update on this?

  2. miryanat commented on Jul 17, 2025

    @miryanat

    @roji @cincuranet any ideas how to fix this? 🙏 our team is hitting a wall with this one

  3. meixger commented on Jul 17, 2025

    @meixger
  4. stefanpavlov commented on Jul 17, 2025

    @stefanpavlov
    Author

    Thank you, I am well aware of SQLite's limitations and possible workarounds. There are a couple of reasons why I want this issue resolved rather than hidden under the carpet.

    1. Unless my understanding of the documentation and code (see here) is wrong, my minimal repro should not fail. The fact that some commands wait for the database to become available and others fail long before the timeout is not inspiring confidence. I'll work around this specific issue but how long until another problem pops (spoiler: it already has)?

    2. I actually have a much bigger problem with a different command which seems like it might be related to this one. A background worker queries for some condition and, if it's met, updates the database. Under certain conditions the update command gets stuck and breaking under a debugger shows it's waiting for the database to stop being busy. The catch is, there is noone else writing to the database and the problem doesn't go away even after I make sure there are no readers either. I was unable to produce a minimal repo of that problem so I was hoping this one will get resolved quickly and maybe they both have the same root cause. Here's an abridged version of the code.

    BackgroundWorker
    public class BackgroundWorker(IServiceScopeFactory scopeFactory) : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            PeriodicTimer timer = new(TimeSpan.FromSeconds(15));
    
            while (await timer.WaitForNextTickAsync(stoppingToken))
            {
                using var scope = scopeFactory.CreateScope();
                await DoWorkAsync(scope, stoppingToken);
            }
        }
    
        private async Task DoWorkAsync(IServiceScope scope, CancellationToken stoppingToken)
        {
            var appDbContext = scope.Resolve<ApplicationDbContext>();
    
            var bucketsThatNeedArchiving = appDbContext.Buckets.TagWith("BucketsThatNeedArchiving")
                .Where(b => b.ArchiveTriggers.StagedFilesSizeExceedsBytes.Enabled && b.StagedFiles.Size >= b.ArchiveTriggers.StagedFilesSizeExceedsBytes.ValueInBytes)
                .Select(b => new { b.Id, b.Name, SizeTrigger = b.ArchiveTriggers.StagedFilesSizeExceedsBytes.ValueInBytes, b.StagedFiles});
    
            foreach (var bucket in bucketsThatNeedArchiving)
            {
                var newStagedFileSize = await appDbContext.Files.TagWith("GetSizeOfNewStagedFilesByBucketId")
                    .Where(f => f.BucketId == bucket.Id && f.Status == FileStatus.Staged && f.JobMarker == null)
                    .SumAsync(f => f.Size, stoppingToken);
                if (newStagedFileSize < bucket.SizeTrigger)
                {
                    continue;
                }
    
                var jobMarker = Guid.NewGuid();
    
                var count = await appDbContext.Files.TagWith("SetFileJob")
                    .Where(f => f.BucketId == bucket.Id && f.Status == FileStatus.Staged && f.JobMarker == null)
                    .ExecuteUpdateAsync(f => f.SetProperty(ff => ff.JobMarker, jobMarker), stoppingToken);
            }
        }
    }
  5. added theissue type on Aug 25, 2025
  6. added a commit that references this issue on Aug 26, 2025
    fb97e41
  7. cincuranet commented on Aug 26, 2025

    @cincuranet
    Contributor

    The problem is that as part of NextResult we call SqliteDataRecord.Dispose and the sqlite3_reset there can return SQLITE_BUSY. Fix in #36657. #36658 tracks bigger scope.

  8. added this to the 11.0.0 milestone on Aug 26, 2025
  9. meixger commented on Aug 29, 2025

    @meixger

    Does the 11.0.0 milestone indicate that it’s already too late for inclusion in EF Core 10?

  10. cincuranet commented on Aug 29, 2025

    @cincuranet
    Contributor

    Yes. It is not going to be in 10.0, maybe servicing. For now 11 it is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions