How to fix better-sqlite3: This statement has already been finalized in SQLite
This error occurs when trying to reuse a prepared SQLite statement that has already been finalized (closed). It typically happens after database connection closure or when the statement object is garbage collected while code still holds a reference to it.
Quick fix
Fixes better-sqlite3: This statement has already been finalized
- Ensure database connection remains open while using statements
- Maintain statement references during asynchronous operations
- Re-prepare statements instead of reusing finalized ones
- Check statement lifecycle in transactions
# better-sqlite3: This statement has already been finalizedbetter-sqlite3: This statement has already been finalized
What this error means
The better-sqlite3 library wraps SQLite prepared statements, and each statement is implicitly finalized once its database connection closes or the statement object is garbage collected. Once `sqlite3_finalize()` runs, the SQLite handle becomes invalid and any subsequent call raises "This statement has already been finalized." This is a safety mechanism to prevent use-after-free errors in the SQLite engine.
Typical symptoms
- Statement methods like `run()`, `get()`, `all()`, or `iterate()` immediately throw the error
- The stack trace shows the error originates from better-sqlite3/sqlite3_step
- The error appears after closing the database connection or after a transaction completes
- The statement object exists in code but every execution attempt fails
- Database connection reports as closed when checked
Common causes
- Calling `db.close()` while still holding references to prepared statements
- Letting a statement object be garbage collected while asynchronous code still tries to use it
- Reusing a statement after SQLite automatically finalized it (no manual `finalize()` in JS API)
- Using a statement after handing it to a transaction or iterator that finalizes it upon completion
How to fix "better-sqlite3: This statement has already been finalized"
Keep your database connection alive until every prepared statement has completed execution. Call db.close() only as the final step after all queries are done. If you need to run queries after closing, reopen the database and prepare fresh statements.
If using statements in async callbacks or timeouts, store references in a higher scope to prevent garbage collection. Dropping the last reference allows the garbage collector to finalize the statement, causing errors on subsequent access.
When you need to execute the same SQL repeatedly, call db.prepare() to create a new statement rather than reusing a finalized one. You can also use stmt.reset() and stmt.bind() for repeated executions with the same prepared statement.
Be aware that some transaction patterns may implicitly finalize statements. Ensure statements used within transactions are not accessed after the transaction completes unless they were prepared outside the transaction scope.
Advanced notes
SQLite strictly prohibits reuse of finalized statement handles. The SQLite C API documentation states that applications must not call any SQLite functions on a statement after sqlite3_finalize() completes. better-sqlite3 automatically finalizes statements when connections close or when statement objects are garbage collected, aligning with SQLite's safety requirements.
Frequently asked questions
- What does "better-sqlite3: This statement has already been finalized" mean?
- The better-sqlite3 library wraps SQLite prepared statements, and each statement is implicitly finalized once its database connection closes or the statement object is garbage collected. " This is a safety mechanism to prevent use-after-free errors in the SQLite engine.
- How do I fix "better-sqlite3: This statement has already been finalized"?
- This error occurs when trying to reuse a prepared SQLite statement that has already been finalized (closed). It typically happens after database connection closure or when the statement object is garbage collected while code still holds a reference to it.
- What causes "better-sqlite3: This statement has already been finalized"?
- Calling db.close() while still holding references to prepared statements Letting a statement object be garbage collected while asynchronous code still tries to use it Reusing a statement after SQLite automatically finalized it (no manual finalize() in JS API)
- Is the "better-sqlite3: This statement has already been finalized" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- ๐SQLite Official Documentation
- ๐sqlite.org - finalize(Official Docs)
- ๐github.com - api.md(GitHub)
- ๐github.com - statement.cpp(GitHub)
- ๐ฌstackoverflow.com - better sqlite3(Stack Overflow)