[BUG] crewai-cli SQLite readers never close their connections (Windows file locks)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 58.8k
- Forks
- 8.5k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 109
Description
Description
Follow-up to #7492 and #7510, which fixed the library-side SQLite backends. The same pattern remains in the third component that opens these databases: crewai-cli.
crewai_cli/checkpoint_cli.py—_list_sqlite,_info_sqlite_latest,_info_sqlite_id,_prune_sqlite, and the--dry-runcount insideprune_checkpointscrewai_cli/task_outputs.py—load_task_outputs(used bycrewai log-tasks-outputs)
All six use with sqlite3.connect(...) as conn: and never call close(). The sqlite3.Connection context manager only commits or rolls back — it does not close the connection. Since Python 3.11 the connection additionally sits in a reference cycle via its statement cache, so the OS file handle survives until a cyclic GC pass.
On Windows the lingering handle locks the checkpoint database (and latest_kickoff_task_outputs.db), so deleting, replacing, or cleaning up the directory afterwards fails with PermissionError: [WinError 32].
Steps to Reproduce
Run any of the SQLite-backed checkpoint commands (or the task-outputs reader), then inspect the connections the command opened:
import os, sqlite3, tempfile
from unittest.mock import patch
import crewai_cli.task_outputs as task_outputs_module
from crewai_cli.task_outputs import load_task_outputs
d = tempfile.mkdtemp()
db = os.path.join(d, "latest_kickoff_task_outputs.db")
with sqlite3.connect(db) as conn:
conn.execute(
"CREATE TABLE latest_kickoff_task_outputs ("
"task_id TEXT PRIMARY KEY, task_key TEXT, expected_output TEXT, "
"output JSON, task_index INTEGER, inputs JSON, "
"was_replayed BOOLEAN, timestamp DATETIME)"
)
conn.commit()
opened = []
real_connect = sqlite3.connect
def tracking_connect(*args, **kwargs):
conn = real_connect(*args, **kwargs)
opened.append(conn)
return conn
with patch.object(task_outputs_module.sqlite3, "connect", tracking_connect):
load_task_outputs(db)
# Expected on a closed connection:
for conn in opened:
conn.execute("SELECT 1") # sqlite3.ProgrammingError: Cannot operate on a closed database.
On main this raises no error: every connection is still open after the command returned. On Windows, deleting db at this point raises PermissionError: [WinError 32] instead.
Expected behavior
Each command closes the connection it opened, so the database file is releasable immediately after use on every platform — the same guarantee #7493 and #7510 established for the library-side backends.
Screenshots/Code snippets
lib/cli/src/crewai_cli/checkpoint_cli.py:
def _list_sqlite(db_path: str) -> list[dict[str, Any]]:
results = []
with sqlite3.connect(db_path) as conn: # commits/rolls back, never closes
...
lib/cli/src/crewai_cli/task_outputs.py:
with sqlite3.connect(db_path) as conn: # commits/rolls back, never closes
...
Operating System
Windows 11 (the file-lock symptom is Windows-only; the leaked handle reproduces on every OS)
Python Version
3.10, 3.11, 3.12
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with lib/cli/src/crewai_cli/checkpoint_cli.py and task_outputs.py, reviewing the six listed SQLite readers and running the load_task_outputs reproduction. Verify that every connection is closed immediately after use, including the prune_checkpoints dry-run count, and confirm the database can be deleted without a Windows file-lock error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, sqlite
- Domain
- cli, databases
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100