{"record":{"id":"e085af5604a0c0c2","repo":"tursodatabase/turso","slug":"5-e085af","errorCode":"5","errorMessage":"SQLite Error 5: 'database is locked'.","messagePattern":"SQLite Error 5: 'database is locked'\\.","errorType":"error_code","errorClass":"SqliteException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data.Sqlite/SqliteBatch.cs","lineNumber":418,"sourceCode":"            }\n\n            mapping.Command.SetRecordsAffected(commandTotal);\n            total = checked(total + commandTotal);\n        }\n\n        return total;\n    }\n\n    private SqliteCommand CreateReaderOwner()\n        => new(_connection) { Transaction = _transaction };\n\n    private void WaitForOpenReader(IReadOnlyList<ManagedSqliteStatement> statements)\n    {\n        if (_connection?.HasOpenReader != true || !statements.Any(SqliteCommand.IsWriteStatement))\n            return;\n\n        Thread.Sleep(TimeSpan.FromSeconds(Timeout));\n        throw new SqliteException(Properties.Resources.SqliteNativeError(5, \"database is locked\"), 5);\n    }\n\n    private async Task WaitForOpenReaderAsync(\n        IReadOnlyList<ManagedSqliteStatement> statements,\n        CancellationToken cancellationToken)\n    {\n        if (_connection?.HasOpenReader != true || !statements.Any(SqliteCommand.IsWriteStatement))\n            return;\n\n        await Task.Delay(TimeSpan.FromSeconds(Timeout), cancellationToken).ConfigureAwait(false);\n        throw new SqliteException(Properties.Resources.SqliteNativeError(5, \"database is locked\"), 5);\n    }\n\n    private static object? ReadScalar(DbDataReader reader)\n    {\n        do\n        {\n            if (reader.FieldCount > 0 && reader.Read())","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/bindings/dotnet/src/Turso.Data.Sqlite/SqliteBatch.cs#L400-L436","documentation":"The synchronous batch execution path simulates SQLite's SQLITE_BUSY (error code 5, 'database is locked'): the connection already has an open data reader and the batch contains a write statement, so executing would mutate the database while a reader holds it. The implementation waits (Thread.Sleep for the command timeout) and then throws SqliteException with code 5.","triggerScenarios":"Executing SqliteBatch.ExecuteNonQuery while another SqliteCommand/reader on the same managed connection still has open results (HasOpenReader == true) and the batch contains INSERT/UPDATE/DELETE/DDL (IsWriteStatement).","commonSituations":"Iterating a DataReader from one command and executing a batch write on the same connection inside the loop; forgetting to close/dispose a reader before writing; draining a SELECT into memory first is required in single-connection managed mode.","solutions":["Close/dispose the open DbDataReader before executing the batch","Buffer the reader results into a list, close the reader, then execute the write batch","Use a separate connection for the write if concurrent read/write is required","Reduce CommandTimeout is irrelevant - the wait is fixed; the fix is not holding the reader"],"exampleFix":"// before\nusing var reader = cmd.ExecuteReader();\nwhile (reader.Read())\n    batch.ExecuteNonQuery(); // throws: reader open\n// after\nvar rows = new List<object[]>();\nusing (var reader = cmd.ExecuteReader())\n    while (reader.Read()) { /* buffer rows */ }\nforeach (var _ in rows)\n    batch.ExecuteNonQuery();","handlingStrategy":"try-catch","validationCode":"if (connection.HasOpenReader && batch.BatchCommands.Any(c => /* IsWriteStatement */ c.CommandText.StartsWith(\"INSERT\", StringComparison.OrdinalIgnoreCase)))\n    throw new InvalidOperationException(\"Close the open reader before executing a write batch.\");","typeGuard":null,"tryCatchPattern":"try { batch.ExecuteNonQuery(); }\ncatch (SqliteException ex) when (ex.SqliteErrorCode == 5)\n{\n    // close readers, then retry once\n    batch.ExecuteNonQuery();\n}","preventionTips":["Always wrap readers in using statements","Never execute writes on a connection while a reader is open; buffer reads first","Use separate connections for concurrent read/write patterns"],"tags":["dotnet","sqlite","database-locked","reader"],"backgroundTag":"database-locked","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-09-06T07:15:26.990Z","contentChangedAt":"2026-09-06T07:15:26.990Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}