Description
Follow-up to #7492 / #7493, which fixed KickoffTaskOutputsSQLiteStorage. The same pattern remains in the two other library-side SQLite backends:
crewai/flow/persistence/sqlite.py — SQLiteFlowPersistence.init_db, save_state, load_state, save_pending_feedback, load_pending_feedback, clear_pending_feedback
crewai/state/provider/sqlite_provider.py — SqliteProvider.checkpoint, prune, from_checkpoint
All nine use with sqlite3.connect(...) as conn: and never call close(). The sqlite3.Connection context manager only commits or rolls back, and since Python 3.11 the connection sits in a reference cycle (statement cache), so the OS file handle survives until a cyclic GC pass.
On Windows the open handle locks flow_states.db / the checkpoint database, so deleting, replacing or cleaning up the directory afterwards fails with PermissionError: [WinError 32]. In this repo's own suite on Windows, test_flow_persistence.py, test_async_human_feedback.py, test_checkpoint.py and test_flow_persistence_factory.py together show 30 failures on main; with this fix they show 3, all of them path-separator assertions unrelated to SQLite.
Steps to Reproduce
import os, tempfile
from crewai.flow.persistence.sqlite import SQLiteFlowPersistence
d = tempfile.mkdtemp()
db = os.path.join(d, "flows.db")
p = SQLiteFlowPersistence(db)
p.save_state("flow-1", "start", {"step": 1})
p.load_state("flow-1")
del p
os.remove(db) # Windows: PermissionError [WinError 32]; Linux: succeeds
Same with SqliteProvider().checkpoint(...) followed by from_checkpoint(...).
Expected behavior
Each operation closes the connection it opened, so the database file is releasable immediately after use on every platform.
Screenshots/Code snippets
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\Users\\...\\Temp\\tmpabc\\flows.db'
Operating System
Windows 11
Python Version
3.13
crewAI Version
main @ c0af9ba (1.15.21+)
crewai-tools Version
same workspace commit
Proposed fix
Same as #7493: wrap each connection in contextlib.closing while keeping the existing commit/rollback context manager. PR with lifecycle and failure-path regression tests follows. After this, the only remaining sites are in the CLI (checkpoint_cli.py, task_outputs.py), which I'd propose as one more small PR.
Disclosure per CONTRIBUTING: this report and the fix were prepared with the help of an AI coding assistant; please apply the llm-generated label.
Description
Follow-up to #7492 / #7493, which fixed
KickoffTaskOutputsSQLiteStorage. The same pattern remains in the two other library-side SQLite backends:crewai/flow/persistence/sqlite.py—SQLiteFlowPersistence.init_db,save_state,load_state,save_pending_feedback,load_pending_feedback,clear_pending_feedbackcrewai/state/provider/sqlite_provider.py—SqliteProvider.checkpoint,prune,from_checkpointAll nine use
with sqlite3.connect(...) as conn:and never callclose(). Thesqlite3.Connectioncontext manager only commits or rolls back, and since Python 3.11 the connection sits in a reference cycle (statement cache), so the OS file handle survives until a cyclic GC pass.On Windows the open handle locks
flow_states.db/ the checkpoint database, so deleting, replacing or cleaning up the directory afterwards fails withPermissionError: [WinError 32]. In this repo's own suite on Windows,test_flow_persistence.py,test_async_human_feedback.py,test_checkpoint.pyandtest_flow_persistence_factory.pytogether show 30 failures onmain; with this fix they show 3, all of them path-separator assertions unrelated to SQLite.Steps to Reproduce
Same with
SqliteProvider().checkpoint(...)followed byfrom_checkpoint(...).Expected behavior
Each operation closes the connection it opened, so the database file is releasable immediately after use on every platform.
Screenshots/Code snippets
Operating System
Windows 11
Python Version
3.13
crewAI Version
main @ c0af9ba (1.15.21+)
crewai-tools Version
same workspace commit
Proposed fix
Same as #7493: wrap each connection in
contextlib.closingwhile keeping the existing commit/rollback context manager. PR with lifecycle and failure-path regression tests follows. After this, the only remaining sites are in the CLI (checkpoint_cli.py,task_outputs.py), which I'd propose as one more small PR.Disclosure per CONTRIBUTING: this report and the fix were prepared with the help of an AI coding assistant; please apply the
llm-generatedlabel.