Skip to content

fix(code): reap langgraph dev server when startup is cancelled - #4629

Merged
Mason Daugherty (mdrxy) merged 4 commits into
mainfrom
wbbradley/process-leak
Jul 10, 2026
Merged

fix(code): reap langgraph dev server when startup is cancelled#4629
Mason Daugherty (mdrxy) merged 4 commits into
mainfrom
wbbradley/process-leak

Conversation

@wbbradley

@wbbradley Will Bradley (wbbradley) commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Problem

Pressing Ctrl+D shortly after launching dcode returns you to the terminal but leaves an orphaned python -m langgraph_cli dev … process running:

$ ps aux | grep deepagent
wbbradley  69643  ...  python3 -m langgraph_cli dev --host 127.0.0.1 --port 59934 --no-browser --no-reload --config .../langgraph.json

This is not intentional — it's a process leak.

Root cause

To make the splash screen appear instantly, the LangGraph server is started in a background Textual worker (_start_server_background) rather than blocking launch. That worker calls start_server_and_get_agent, which spawns the langgraph dev subprocess early (inside ServerProcess.start()) and then spends a few seconds polling /ok for health + graph readiness.

If the user quits during that window:

  1. super().exit() tears down Textual, which cancels all workers, injecting asyncio.CancelledError into the in-flight server.start().
  2. start_server_and_get_agent guarded cleanup with except Exception: — but CancelledError is a BaseException, not an Exception, so server.stop() was skipped and the exception re-raised.
  3. Because the function never returned, DeepAgentsApp._server_proc was never assigned, so the belt-and-suspenders finally in run_textual_app also saw None and skipped cleanup.

Net result: the langgraph dev subprocess is orphaned. When the server has fully finished starting before the quit, stop() runs correctly and there is no leak — the leak is specific to quitting during startup.

Fix

Catch BaseException (which includes asyncio.CancelledError) around server.start() / wait_for_graph_ready() so a cancelled startup still stops the half-started subprocess, then re-raise to preserve cancellation/shutdown semantics. This matches the existing cleanup-on-cancel-and-reraise pattern already used in skills/trust.py.

@github-actions github-actions Bot added dcode Related to `deepagents-code` fix A bug fix (PATCH) internal User is a member of the `langchain-ai` GitHub organization size: S 50-199 LOC labels Jul 10, 2026

@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: No issues found

Open SWE reviewed this PR and found no potential bugs to report.

Open in WebView Open SWE trace

The langgraph dev server starts in a background worker so the TUI paints
immediately. `ServerProcess.start()` spawns the subprocess before returning,
but the app only records the `ServerProcess` on success. If the user quits
(Ctrl+D) before the health check completes, the worker is cancelled
mid-`start()`. `start_server_and_get_agent` guarded its cleanup with
`except Exception`, which does not catch `asyncio.CancelledError` (a
`BaseException`), so `server.stop()` was skipped and the `langgraph dev`
subprocess was orphaned.

Catch `BaseException` so a cancelled startup also stops the half-started
server, then re-raise to preserve cancellation/shutdown semantics.
@aolsenjazz

Copy link
Copy Markdown
Contributor

LGTM, Mason Daugherty (@mdrxy) would you confirm that widening this exception type is the most-correct solution?

@github-actions github-actions Bot added size: M 200-499 LOC and removed size: S 50-199 LOC labels Jul 10, 2026
@mdrxy
Mason Daugherty (mdrxy) merged commit 904ff05 into main Jul 10, 2026
51 of 53 checks passed
@mdrxy
Mason Daugherty (mdrxy) deleted the wbbradley/process-leak branch July 10, 2026 15:30
Mason Daugherty (mdrxy) added a commit that referenced this pull request Jul 13, 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`. The published GitHub release body is extracted from the
merged `CHANGELOG.md` by `release.yml`, not from this PR description._

---


##
[0.1.37](deepagents-code==0.1.36...deepagents-code==0.1.37)
(2026-07-13)

### Features

* Add Meta model provider
([#4650](#4650))
([70829c5](70829c5))
* Set `prompt_cache_key` for OpenAI models
([#4632](#4632))
([8cf57ac](8cf57ac))
* Support Fireworks `/routers` model ids
([#4591](#4591))
([1c08d27](1c08d27))
* `/model` Ctrl+N toggle for names vs raw specs
([#4592](#4592))
([518c322](518c322))
* `/tools` slash command
([#4649](#4649))
([b1600a8](b1600a8))
* Add `-s` alias for `--skill`
([#4620](#4620))
([c9b7ac2](c9b7ac2))
* Configurable chat cursor style
([#4687](#4687))
([a22484b](a22484b))
* Expand environment variables in MCP config
([#4681](#4681))
([4f5d7be](4f5d7be))
* Hide diff widget for credential files
([#4593](#4593))
([4c49a24](4c49a24))
* In-app Debug Console
([#4564](#4564))
([4f94a30](4f94a30))
* Offer abort in `/threads` cwd-switch prompt
([#4583](#4583))
([aaeac99](aaeac99))
* Resume threads in-TUI with `/threads -r [ID]`
([#4609](#4609))
([d442673](d442673))
* Show `(debug enabled)` on splash when `DEEPAGENTS_CODE_DEBUG` is set
([#4584](#4584))
([f10b877](f10b877))

### Bug Fixes

* Avoid repeated startup auto-update stalls
([#4648](#4648))
([12a9c9d](12a9c9d))
* Infer Fireworks provider from qualified model IDs
([#4594](#4594))
([4d2aa8a](4d2aa8a))
* Capture input typed before TUI startup
([#4684](#4684))
([ef9a4a8](ef9a4a8))
* Detach owned `langgraph dev` server from terminal
([#4642](#4642))
([d1f3afe](d1f3afe))
* Infer additional model providers
([#4675](#4675))
([4ceed24](4ceed24))
* Preserve `Ctrl+D` deletion in non-empty input
([#4626](#4626))
([306bd89](306bd89))
* Quit with `Ctrl+D` at end of prompt
([#4678](#4678))
([2f8c111](2f8c111))
* Reap langgraph dev server when startup is cancelled
([#4629](#4629))
([904ff05](904ff05))
* Reject `--auto-approve` in headless mode
([#4617](#4617))
([997be16](997be16))
* Route explicit `--stdin` + `--skill` to headless path
([#4611](#4611))
([724e24a](724e24a))
* Skip Esc prompt-restore once output generation begins
([#4582](#4582))
([14f384f](14f384f))
* Remove misleading agent names from help
([#4671](#4671))
([ac15732](ac15732))
* Support plain `exit` quit command
([#4543](#4543))
([e6f10a1](e6f10a1))
* Sync `ask_user` active-question highlight with focus
([#4599](#4599))
([e4c29b5](e4c29b5))
* Wrap MCP viewer navigation
([#4677](#4677))
([cffc732](cffc732))

### Performance Improvements

* Load MCP servers concurrently during graph build
([#4659](#4659))
([c5345cc](c5345cc))

---

_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: Mason Daugherty <github@mdrxy.com>
Marcelo5444 pushed a commit to Marcelo5444/deepagents that referenced this pull request Jul 30, 2026
…hain-ai#4629)

## Problem

Pressing `Ctrl+D` shortly after launching `dcode` returns you to the
terminal but leaves an orphaned `python -m langgraph_cli dev …` process
running:

```
$ ps aux | grep deepagent
wbbradley  69643  ...  python3 -m langgraph_cli dev --host 127.0.0.1 --port 59934 --no-browser --no-reload --config .../langgraph.json
```

This is not intentional — it's a process leak.

## Root cause

To make the splash screen appear instantly, the LangGraph server is
started in a background Textual worker (`_start_server_background`)
rather than blocking launch. That worker calls
`start_server_and_get_agent`, which spawns the `langgraph dev`
subprocess early (inside `ServerProcess.start()`) and then spends a few
seconds polling `/ok` for health + graph readiness.

If the user quits during that window:

1. `super().exit()` tears down Textual, which **cancels all workers**,
injecting `asyncio.CancelledError` into the in-flight `server.start()`.
2. `start_server_and_get_agent` guarded cleanup with `except Exception:`
— but `CancelledError` is a `BaseException`, **not** an `Exception`, so
`server.stop()` was skipped and the exception re-raised.
3. Because the function never returned, `DeepAgentsApp._server_proc` was
never assigned, so the belt-and-suspenders `finally` in
`run_textual_app` also saw `None` and skipped cleanup.

Net result: the `langgraph dev` subprocess is orphaned. When the server
has fully finished starting before the quit, `stop()` runs correctly and
there is no leak — the leak is specific to quitting *during* startup.

## Fix

Catch `BaseException` (which includes `asyncio.CancelledError`) around
`server.start()` / `wait_for_graph_ready()` so a cancelled startup still
stops the half-started subprocess, then re-raise to preserve
cancellation/shutdown semantics. This matches the existing
cleanup-on-cancel-and-reraise pattern already used in `skills/trust.py`.

---------

Co-authored-by: Mason Daugherty <github@mdrxy.com>
Co-authored-by: Mason Daugherty <mason@langchain.dev>
Marcelo5444 pushed a commit to Marcelo5444/deepagents that referenced this pull request Jul 30, 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`. The published GitHub release body is extracted from the
merged `CHANGELOG.md` by `release.yml`, not from this PR description._

---


##
[0.1.37](langchain-ai/deepagents@deepagents-code==0.1.36...deepagents-code==0.1.37)
(2026-07-13)

### Features

* Add Meta model provider
([langchain-ai#4650](langchain-ai#4650))
([70829c5](langchain-ai@70829c5))
* Set `prompt_cache_key` for OpenAI models
([langchain-ai#4632](langchain-ai#4632))
([8cf57ac](langchain-ai@8cf57ac))
* Support Fireworks `/routers` model ids
([langchain-ai#4591](langchain-ai#4591))
([1c08d27](langchain-ai@1c08d27))
* `/model` Ctrl+N toggle for names vs raw specs
([langchain-ai#4592](langchain-ai#4592))
([518c322](langchain-ai@518c322))
* `/tools` slash command
([langchain-ai#4649](langchain-ai#4649))
([b1600a8](langchain-ai@b1600a8))
* Add `-s` alias for `--skill`
([langchain-ai#4620](langchain-ai#4620))
([c9b7ac2](langchain-ai@c9b7ac2))
* Configurable chat cursor style
([langchain-ai#4687](langchain-ai#4687))
([a22484b](langchain-ai@a22484b))
* Expand environment variables in MCP config
([langchain-ai#4681](langchain-ai#4681))
([4f5d7be](langchain-ai@4f5d7be))
* Hide diff widget for credential files
([langchain-ai#4593](langchain-ai#4593))
([4c49a24](langchain-ai@4c49a24))
* In-app Debug Console
([langchain-ai#4564](langchain-ai#4564))
([4f94a30](langchain-ai@4f94a30))
* Offer abort in `/threads` cwd-switch prompt
([langchain-ai#4583](langchain-ai#4583))
([aaeac99](langchain-ai@aaeac99))
* Resume threads in-TUI with `/threads -r [ID]`
([langchain-ai#4609](langchain-ai#4609))
([d442673](langchain-ai@d442673))
* Show `(debug enabled)` on splash when `DEEPAGENTS_CODE_DEBUG` is set
([langchain-ai#4584](langchain-ai#4584))
([f10b877](langchain-ai@f10b877))

### Bug Fixes

* Avoid repeated startup auto-update stalls
([langchain-ai#4648](langchain-ai#4648))
([12a9c9d](langchain-ai@12a9c9d))
* Infer Fireworks provider from qualified model IDs
([langchain-ai#4594](langchain-ai#4594))
([4d2aa8a](langchain-ai@4d2aa8a))
* Capture input typed before TUI startup
([langchain-ai#4684](langchain-ai#4684))
([ef9a4a8](langchain-ai@ef9a4a8))
* Detach owned `langgraph dev` server from terminal
([langchain-ai#4642](langchain-ai#4642))
([d1f3afe](langchain-ai@d1f3afe))
* Infer additional model providers
([langchain-ai#4675](langchain-ai#4675))
([4ceed24](langchain-ai@4ceed24))
* Preserve `Ctrl+D` deletion in non-empty input
([langchain-ai#4626](langchain-ai#4626))
([306bd89](langchain-ai@306bd89))
* Quit with `Ctrl+D` at end of prompt
([langchain-ai#4678](langchain-ai#4678))
([2f8c111](langchain-ai@2f8c111))
* Reap langgraph dev server when startup is cancelled
([langchain-ai#4629](langchain-ai#4629))
([904ff05](langchain-ai@904ff05))
* Reject `--auto-approve` in headless mode
([langchain-ai#4617](langchain-ai#4617))
([997be16](langchain-ai@997be16))
* Route explicit `--stdin` + `--skill` to headless path
([langchain-ai#4611](langchain-ai#4611))
([724e24a](langchain-ai@724e24a))
* Skip Esc prompt-restore once output generation begins
([langchain-ai#4582](langchain-ai#4582))
([14f384f](langchain-ai@14f384f))
* Remove misleading agent names from help
([langchain-ai#4671](langchain-ai#4671))
([ac15732](langchain-ai@ac15732))
* Support plain `exit` quit command
([langchain-ai#4543](langchain-ai#4543))
([e6f10a1](langchain-ai@e6f10a1))
* Sync `ask_user` active-question highlight with focus
([langchain-ai#4599](langchain-ai#4599))
([e4c29b5](langchain-ai@e4c29b5))
* Wrap MCP viewer navigation
([langchain-ai#4677](langchain-ai#4677))
([cffc732](langchain-ai@cffc732))

### Performance Improvements

* Load MCP servers concurrently during graph build
([langchain-ai#4659](langchain-ai#4659))
([c5345cc](langchain-ai@c5345cc))

---

_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: Mason Daugherty <github@mdrxy.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` 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.

3 participants