From 1289eb05894eaed2d0e868e6901231c2683989d2 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Thu, 30 Oct 2025 10:29:45 -0700 Subject: [PATCH] Fix SQLite locking issue in execute_write_script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The execute_write_script() method was causing SQLite database locking errors when multiple executescript() calls ran in quick succession. Root cause: SQLite's executescript() method has special behavior - it implicitly commits any pending transaction and operates in autocommit mode. However, execute_write_script() was passing these calls through execute_write_fn() with the default transaction=True, which wrapped the executescript() call in a transaction context (with conn:). This created a conflict where sequential executescript() calls would cause the second call to fail with "OperationalError: database table is locked: sqlite_master" because the sqlite_master table was still locked from the first operation's implicit commit. Fix: Pass transaction=False to execute_write_fn() since executescript() manages its own transactions and should not be wrapped in an additional transaction context. This was causing test_hook_extra_body_script to fail because the internal database initialization (which calls executescript twice in succession) would fail, preventing the application from rendering pages correctly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- datasette/database.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/datasette/database.py b/datasette/database.py index b74f02bb..13baa1d9 100644 --- a/datasette/database.py +++ b/datasette/database.py @@ -143,7 +143,9 @@ class Database: return conn.executescript(sql) with trace("sql", database=self.name, sql=sql.strip(), executescript=True): - results = await self.execute_write_fn(_inner, block=block) + results = await self.execute_write_fn( + _inner, block=block, transaction=False + ) return results async def execute_write_many(self, sql, params_seq, block=True):