Skip to content

fix(code): stop leaking turn coroutines and sqlite handles - #5218

Merged
Mason Daugherty (mdrxy) merged 6 commits into
mainfrom
mdrxy/code/test-warnings
Aug 4, 2026
Merged

fix(code): stop leaking turn coroutines and sqlite handles#5218
Mason Daugherty (mdrxy) merged 6 commits into
mainfrom
mdrxy/code/test-warnings

Conversation

@mdrxy

@mdrxy Mason Daugherty (mdrxy) commented Jul 31, 2026

Copy link
Copy Markdown
Member

Interrupting a turn, or exiting while a background thread-cache refresh is in flight, no longer strands an unawaited coroutine or an open SQLite handle.


The unit suite emitted three families of warnings, all at teardown. Two are ours and are fixed here; the third is upstream and is filtered.

An unawaited turn coroutine

_send_to_agent handed run_worker an already-built _run_agent_task coroutine. Textual never runs the work of a worker cancelled before its first event-loop step, so that coroutine was finalized unawaited — a RuntimeWarning, and (once interpreter teardown had gone far enough to break the import machinery its cleanup relies on) an unraisable KeyError: '__import__'. Passing a callable means the coroutine only exists if the worker actually runs, so there is nothing to strand. Several tests were closing that coroutine by hand purely to silence the warning; those workarounds are gone, and a new test pins the callable contract.

Where it started: #5196. Handing run_worker a coroutine dates all the way back to the original Textual REPL (#686), but it was harmless until something cancelled a worker before its first step. #5196 added the recovery path for exactly that situation along with the tests that exercise it. Its parent commit runs the app test module with zero never awaited warnings; #5196 itself produces three.

An unclosed SQLite handle

aiosqlite opens the database on its worker thread and hands the raw sqlite3.Connection back through a future, recording it on the connection only when the awaiting coroutine resumes. A cancel landing anywhere in that window left the handle unreachable from the cleanup that follows, so the garbage collector reported ResourceWarning: unclosed database. There are two halves to the window, and both are now covered:

  • Cancelled while the worker is still opening, the library has no handle recorded yet, so the cleanup it queues closes nothing. The session module now records the handle from the worker thread the moment the connector returns.
  • Cancelled after the handle is delivered but before the coroutine resumes, the library clears its own reference before that queued cleanup can run — so it again closes nothing. The guard now also queues an explicit close ahead of the library's cleanup, while the handle is still reachable.

Both closes run on the thread that opened the handle, and closing twice is a no-op, so neither disturbs a normal shutdown. get_checkpointer builds its connection through the same helper rather than AsyncSqliteSaver.from_conn_string, so it gets the same guard.

Where it started: #5174. The prewarm that reads the session database has existed since #1481, but it ran once at startup, so it had normally finished before anything cancelled it. #5174 re-fires it after every turn, which reliably leaves a session-DB read in flight when a test app exits. Counting handles that aiosqlite opened and never closed across the goal-command tests: zero on the parent commit, fourteen on #5174.

A typing deprecation from google-genai

google.genai.types builds a union alias out of typing._UnionGenericAlias, which CPython 3.14 deprecates, and it fires at import before any of this package's code runs. This one is not a regression from any change here — deepagents-code has been tested on the 3.14 leg since the package was created in #3027, and the warning appears wherever a test imports the Google integration. It is tracked upstream as googleapis/python-genai#1640 and still unfixed as of google-genai 2.13.0, so it is filtered narrowly (message, category, and module) rather than worked around.

Made by Open SWE

Two teardown leaks surfaced as pytest warnings. The agent turn was handed
to `run_worker` as a pre-built coroutine, which a worker cancelled before
its first event-loop step never awaits. And `aiosqlite` only records its
sqlite handle when the awaiting coroutine resumes, so a background worker
cancelled mid-connect stranded the handle for the garbage collector.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
@github-actions github-actions Bot added dcode Related to `deepagents-code` dependencies Pull requests that update a dependency file fix A bug fix (PATCH) internal User is a member of the `langchain-ai` GitHub organization size: M 200-499 LOC labels Jul 31, 2026
@mdrxy
Mason Daugherty (mdrxy) marked this pull request as ready for review July 31, 2026 05:23

@open-swe open-swe Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open SWE Review found 1 potential issue.

Open in WebView Open SWE trace

Comment thread libs/code/deepagents_code/sessions.py
Mason Daugherty (mdrxy) and others added 3 commits July 31, 2026 05:46
The handle guard only covered a cancel arriving while the worker thread
was still opening the database. A cancel arriving after the handle was
delivered but before the awaiting coroutine resumed still leaked it:
aiosqlite drops its own reference before the cleanup it queued can run.
Queue the close ahead of that cleanup so both halves of the window are
covered.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
@mdrxy
Mason Daugherty (mdrxy) merged commit 994799b into main Aug 4, 2026
81 checks passed
@mdrxy
Mason Daugherty (mdrxy) deleted the mdrxy/code/test-warnings branch August 4, 2026 19:14
Mason Daugherty (mdrxy) pushed a commit that referenced this pull request Aug 6, 2026
> [!CAUTION]
> Merging this PR will automatically publish to **PyPI** and create a
**GitHub release**.

For the full release process, see
[`.github/RELEASING.md`](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md).

---

_Release notes preview: keep this section in sync with the package
`CHANGELOG.md`. Publish reads the merged CHANGELOG via `release.yml`,
not this PR description — keep them aligned anyway so the PR stays an
accurate historical record for reviewers and anyone returning later._

---


##
[0.1.53](deepagents-code==0.1.52...deepagents-code==0.1.53)
(2026-08-06)

### Features

- Added pricing coverage with Baseten built-in overrides and local
fallback overrides when `genai-prices` is missing data
([#5312](#5312),
[#5304](#5304)).
- Suggest compacting large resumed threads
([#5318](#5318)).
- Added terminal program trace metadata
([#5329](#5329)).

### Bug Fixes

- Preserved runtime offload archive routing
([#5328](#5328)).
- Always restart after a successful startup auto-update
([#5317](#5317)).
- Fixed leaked turn coroutines and SQLite handles
([#5218](#5218)).
- Keep MCP shutdown-race tracebacks from appearing in the terminal
([#5325](#5325)).
- Open the `/auto model` selector immediately while connecting
([#5341](#5341)).
- Route failures to `PostToolUseFailure`
([#5315](#5315)).
- Use dismissed copy for ask-user prompts
([#5331](#5331)).

_End release notes preview._

---

> [!NOTE]
> A **New Contributors** section is appended to the GitHub release notes
automatically at publish time (see [Release
Pipeline](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md#release-pipeline),
step 2).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: langchain-oss-automated-triage[bot] <248757908+langchain-oss-automated-triage[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dcode Related to `deepagents-code` dependencies Pull requests that update a dependency file fix A bug fix (PATCH) internal User is a member of the `langchain-ai` GitHub organization size: M 200-499 LOC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant