Skip to content

agent_ui: Fix session equality check for reloading retained threads#53992

Merged
benbrandt merged 5 commits intomainfrom
reproduce-session-disassociation
Apr 16, 2026
Merged

agent_ui: Fix session equality check for reloading retained threads#53992
benbrandt merged 5 commits intomainfrom
reproduce-session-disassociation

Conversation

@nathansobo
Copy link
Copy Markdown
Contributor

Summary

Adds three tests that exercise session disassociation ("Session not found" after reopening a thread). The third test fails, reproducing the bug.

Root cause

A retained ConversationView with a thread_error receives AgentServersUpdated, which triggers reset()close_all_sessions → state transitions to Loading. When the user then reopens the same session via open_thread, load_agent_thread's has_session check returns false (because the retained view is in Loading state, not Connected), so a second ConversationView is created for the same session. Both views' async load tasks complete and both transition to Connected with the same session ID. When the retained view is later cleaned up, its on_releaseclose_all_sessions removes the session from the connection, leaving the active view stranded with a dead session.

Tests

Test Status What it verifies
test_open_thread_on_visible_session_does_not_disassociate_it ✅ Pass load_agent_thread short-circuits when session is already active
test_retained_thread_cleanup_does_not_disassociate_reopened_session ✅ Pass Eviction + reopen cycle works (close-then-reload)
test_retained_thread_reset_race_disassociates_session Fail Reproduces the race described above

cc @bennetbo @ConradIrwin

Release Notes:

  • N/A

Add three tests for session disassociation ("Session not found" after
reopening a thread):

1. test_open_thread_on_visible_session_does_not_disassociate_it (passes)
   Verifies load_agent_thread short-circuits when the session is already
   the active view.

2. test_retained_thread_cleanup_does_not_disassociate_reopened_session (passes)
   Verifies that eviction + reopen cycle works correctly.

3. test_retained_thread_reset_race_disassociates_session (FAILS - reproduces bug)
   A retained ConversationView with a thread_error receives
   AgentServersUpdated, calls reset() (state -> Loading), and then
   open_thread creates a second ConversationView for the same session
   because has_session returns false on the Loading state. When the
   retained view is later cleaned up, its on_release -> close_all_sessions
   removes the session from the connection, stranding the active view.
@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Apr 15, 2026
@zed-community-bot zed-community-bot Bot added the staff Pull requests authored by a current member of Zed staff label Apr 15, 2026
@nathansobo nathansobo requested review from benbrandt and bennetbo and removed request for ConradIrwin and bennetbo April 15, 2026 16:00
@benbrandt benbrandt changed the title agent_ui: Reproduce session disassociation race in retained threads agent_ui: Fix session equality check for reloading retained threads Apr 16, 2026
let has_session = |cv: &Entity<ConversationView>| -> bool {
cv.read(cx)
.active_thread()
.is_some_and(|tv| tv.read(cx).thread.read(cx).session_id() == &session_id)
Copy link
Copy Markdown
Member

@benbrandt benbrandt Apr 16, 2026

Choose a reason for hiding this comment

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

The issue was Active thread session id could be a subagent or we could be in a loading/error state and the active thread isn't set yet. But we already know the session id, so we sholuld be using that instead

benbrandt and others added 2 commits April 16, 2026 15:19
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
@benbrandt benbrandt enabled auto-merge (squash) April 16, 2026 13:21
@benbrandt benbrandt merged commit 3bb0b49 into main Apr 16, 2026
31 checks passed
@benbrandt benbrandt deleted the reproduce-session-disassociation branch April 16, 2026 13:26
@benbrandt
Copy link
Copy Markdown
Member

/cherry-pick preview

github-actions Bot pushed a commit that referenced this pull request Apr 16, 2026
…53992)

## Summary

Adds three tests that exercise session disassociation ("Session not
found" after reopening a thread). The third test **fails**, reproducing
the bug.

### Root cause

A retained `ConversationView` with a `thread_error` receives
`AgentServersUpdated`, which triggers `reset()` → `close_all_sessions` →
state transitions to `Loading`. When the user then reopens the same
session via `open_thread`, `load_agent_thread`'s `has_session` check
returns `false` (because the retained view is in `Loading` state, not
`Connected`), so a **second** `ConversationView` is created for the same
session. Both views' async load tasks complete and both transition to
`Connected` with the same session ID. When the retained view is later
cleaned up, its `on_release` → `close_all_sessions` removes the session
from the connection, leaving the active view stranded with a dead
session.

### Tests

| Test | Status | What it verifies |
|------|--------|-----------------|
| `test_open_thread_on_visible_session_does_not_disassociate_it` | ✅
Pass | `load_agent_thread` short-circuits when session is already active
|
| `test_retained_thread_cleanup_does_not_disassociate_reopened_session`
| ✅ Pass | Eviction + reopen cycle works (close-then-reload) |
| `test_retained_thread_reset_race_disassociates_session` | ❌ **Fail** |
Reproduces the race described above |

cc @bennetbo @ConradIrwin

Release Notes:

- N/A

---------

Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
@eholk eholk mentioned this pull request Apr 16, 2026
18 tasks
eholk pushed a commit that referenced this pull request Apr 16, 2026
…53992)

## Summary

Adds three tests that exercise session disassociation ("Session not
found" after reopening a thread). The third test **fails**, reproducing
the bug.

### Root cause

A retained `ConversationView` with a `thread_error` receives
`AgentServersUpdated`, which triggers `reset()` → `close_all_sessions` →
state transitions to `Loading`. When the user then reopens the same
session via `open_thread`, `load_agent_thread`'s `has_session` check
returns `false` (because the retained view is in `Loading` state, not
`Connected`), so a **second** `ConversationView` is created for the same
session. Both views' async load tasks complete and both transition to
`Connected` with the same session ID. When the retained view is later
cleaned up, its `on_release` → `close_all_sessions` removes the session
from the connection, leaving the active view stranded with a dead
session.

### Tests

| Test | Status | What it verifies |
|------|--------|-----------------|
| `test_open_thread_on_visible_session_does_not_disassociate_it` | ✅
Pass | `load_agent_thread` short-circuits when session is already active
|
| `test_retained_thread_cleanup_does_not_disassociate_reopened_session`
| ✅ Pass | Eviction + reopen cycle works (close-then-reload) |
| `test_retained_thread_reset_race_disassociates_session` | ❌ **Fail** |
Reproduces the race described above |

cc @bennetbo @ConradIrwin

Release Notes:

- N/A

---------

Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
eholk added a commit that referenced this pull request Apr 16, 2026
We're doing another preview release today to get our latest parallel
agents features out there. This PR is a rollup of all the changes we
need to cherry pick.

- [x] 7a26e48 from
#54081
- [x] #54066
- [x] #53992
- [x] #54079
- [x] #54057
- [x] #54056
- [x] #54052
- [x] #53999
- [x] #54009
- [x] #53539 (already cherry
picked as 25e02cb)
- [x] #54070
- [x] #54053
- fix `run_tests.yml`: 67e92b5
- [x] #53979
- [x] #53884
- [x] #54067
- [x] #54014 (already on
branch)
- [x] #54030 (already on
branch)
- [x] #54094

Release Notes:

- N/A

---------

Co-authored-by: Lukas Wirth <me@lukaswirth.dev>
Co-authored-by: Bennet Bo Fenner <bennet@zed.dev>
Co-authored-by: Nathan Sobo <nathan@zed.dev>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
Co-authored-by: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
Co-authored-by: Neel <neel@zed.dev>
Co-authored-by: Richard Feldman <richard@zed.dev>
G36maid pushed a commit to G36maid/zed that referenced this pull request Apr 29, 2026
…ed-industries#53992)

## Summary

Adds three tests that exercise session disassociation ("Session not
found" after reopening a thread). The third test **fails**, reproducing
the bug.

### Root cause

A retained `ConversationView` with a `thread_error` receives
`AgentServersUpdated`, which triggers `reset()` → `close_all_sessions` →
state transitions to `Loading`. When the user then reopens the same
session via `open_thread`, `load_agent_thread`'s `has_session` check
returns `false` (because the retained view is in `Loading` state, not
`Connected`), so a **second** `ConversationView` is created for the same
session. Both views' async load tasks complete and both transition to
`Connected` with the same session ID. When the retained view is later
cleaned up, its `on_release` → `close_all_sessions` removes the session
from the connection, leaving the active view stranded with a dead
session.

### Tests

| Test | Status | What it verifies |
|------|--------|-----------------|
| `test_open_thread_on_visible_session_does_not_disassociate_it` | ✅
Pass | `load_agent_thread` short-circuits when session is already active
|
| `test_retained_thread_cleanup_does_not_disassociate_reopened_session`
| ✅ Pass | Eviction + reopen cycle works (close-then-reload) |
| `test_retained_thread_reset_race_disassociates_session` | ❌ **Fail** |
Reproduces the race described above |

cc @bennetbo @ConradIrwin

Release Notes:

- N/A

---------

Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement staff Pull requests authored by a current member of Zed staff

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants