Skip to content

Add ViewHandle::try_update and use it to guard shared session retention - #15695

Merged
acarl005 merged 8 commits into
masterfrom
factory/guard-closed-retention-view
Sep 1, 2026
Merged

Add ViewHandle::try_update and use it to guard shared session retention#15695
acarl005 merged 8 commits into
masterfrom
factory/guard-closed-retention-view

Conversation

@warp-agent-staging

@warp-agent-staging warp-agent-staging Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes the Window does not exist fatal in TerminalDriver::extend_shared_session_retention after the terminal window and view mapping are already gone.

Sentry: WARP-CLIENT-DEV-YVH (7703530317).

A ViewHandle keeps the view's ref count alive but does not keep its window open, so a spawned task that resolves after close used to panic in ViewHandle::update. The shared-session retention path on EnvironmentSetupFailed / SetupCommandExitedShell hits that race.

ViewHandle::try_update is the fallible counterpart. Checkout failures come from take_view_for_update, which now returns Result. try_update_view propagates that result. update_view still panics with "Window does not exist" / "Circular view update" so existing callers keep failing loudly.

ViewUpdateError keeps the two failures distinct: WindowClosed is an expected teardown race and is non-actionable, so report_error! only warns; CircularUpdate is a bug and reaches Sentry.

Start at take_view_for_update in crates/warpui_core/src/core/app.rs, then the panic mapping in AppContext::update_view.

Linked Issue

  • The linked issue is labeled ready-to-spec or ready-to-implement.
  • Where appropriate, screenshots or a short video of the implementation are included below (especially for user-visible or UI changes).

Tracked as Sentry issue WARP-CLIENT-DEV-YVH / 7703530317 rather than a GitHub issue.

Testing

warpui_core tests cover a successful try_update plus WindowClosed and CircularUpdate error propagation.

Commands:

  • cargo nextest run -p warpui_core — 323 passed, 7 skipped.

  • cargo nextest run -p warpui_core -E 'test(try_update)' — 3 passed.

  • cargo clippy -p warp -p warpui_core --all-targets --tests -- -D warnings — clean.

  • ./script/format — clean.

  • I have manually tested my changes locally with ./script/run

Screenshots / Videos

N/A — this is a panic guard on a closed-window agent-driver path.

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-BUG-FIX: Fix a crash that could occur when extending a shared session after its terminal window had already closed.

Closing the terminal window removes the view mapping, so
TerminalDriver::extend_shared_session_retention panicked with
"Window does not exist" when it later called ViewHandle::update.
Upgrade the weak handle first and no-op if the view is already gone.
@warp-agent-staging

Copy link
Copy Markdown
Contributor Author

This PR was generated with Warp.

Comment @warp-factory on this PR to send it follow-up work.

View run View conversation

@advait-m
advait-m marked this pull request as ready for review September 1, 2026 01:00

@warp-factories warp-factories Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Overview

Guards extend_shared_session_retention against the "Window does not exist" panic when the terminal window closed before the call, matching handle_window_closed's actual removal semantics; net position is approve-leaning with two non-blocking suggestions.

Concerns

  • Several sibling call sites on TerminalDriver (execute_command, send_text_to_cli, apply_share_requests, cd/cd_silent, block_snapshot, find_first_match_in_block_output, current_directory) call self.terminal_view.update/read/as_ref the same way this one used to, so they carry the identical "Window does not exist" panic risk if the window closes while the driver is still alive. Worth a follow-up to extract a shared "upgrade-or-return" guard and audit those paths, since this one only reached Sentry because it happened to be exercised.

Verdict

Checks: build n/a (no local toolchain to compile), tests n/a (not independently re-run; PR description reports the new/existing regression tests and cargo clippy/./script/format passing), CI in progress (Linux/macOS/Windows test and clippy jobs pending at review time), visual proof n/a (non-user-visible panic guard)

Found: 0 critical, 0 important, 2 suggestions, 0 nits

Comment thread app/src/ai/agent_sdk/driver/terminal.rs Outdated
self.terminal_view.update(ctx, |terminal, ctx| {
let Some(terminal_view) = self.terminal_view.downgrade().upgrade(ctx) else {
return;
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: this early return is silent, unlike the sibling "not an active sharer" branch below it which logs a log::warn!. Since this exact spot reached Sentry as a crash, a log::info!/log::debug! here (e.g. "Skipping shared session retention extension: terminal window already closed") would make it easier to confirm in production logs that this guard — rather than some other path — handled the closed-window case.

Comment thread app/src/ai/agent_sdk/driver/terminal.rs Outdated
ctx: &mut ModelContext<Self>,
) {
self.terminal_view.update(ctx, |terminal, ctx| {
let Some(terminal_view) = self.terminal_view.downgrade().upgrade(ctx) else {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This .downgrade().upgrade() pattern to check if ViewHandle is alive is very ugly - working on a better approach here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Understood — I’ll leave the branch unchanged and keep this thread open while you explore the preferred handle-liveness API.

Responding as wilson: Open session · View in factory

advait-m and others added 2 commits August 31, 2026 18:45
A ViewHandle keeps the view's ref count alive but does not keep its window
open, so update() panics with "Window does not exist" whenever a spawned
task resolves after the window was closed.

The only existing way to probe for that was downgrade().upgrade(), which
also consults the window's view map. A view is absent from that map while
an update against it is in flight, so upgrade() reports a live but
reentrantly-borrowed view as gone -- turning what should be a loud
"Circular view update" panic into a silent no-op.

try_update guards on the window alone, so a torn-down window yields None
while a reentrant update still panics as before.

Co-Authored-By: Warp <agent@warp.dev>
Replaces the downgrade().upgrade() liveness probe with try_update, so a
reentrantly-borrowed terminal view is no longer misreported as a closed
window, and logs when the retention update is skipped so the shutdown
race is visible.

Co-Authored-By: Warp <agent@warp.dev>
@advait-m advait-m changed the title Guard closed terminal view during shared session retention Add ViewHandle::try_update and use it to guard shared session retention Sep 1, 2026
advait-m and others added 2 commits September 1, 2026 11:09
Rust convention is that a try_ method does not panic: RefCell::try_borrow_mut
returns Err for exactly the reentrancy that borrow_mut panics on. try_update
still panicked with "Circular view update" when the view was already checked
out further up the stack, which violates that contract.

Report both checkout failures through a typed ViewUpdateError instead, so the
two stay distinguishable and per-variant is_actionable() puts the
classification where it belongs: WindowClosed is an expected teardown race and
only warns, while CircularUpdate is a bug that reaches Sentry. The panicking
update_view is unchanged, so callers that never expect reentrancy still fail
loudly.

Co-Authored-By: Warp <agent@warp.dev>
take_view_for_update is where checkout actually fails, so it now returns
Result. try_update_view propagates that error. update_view keeps the
legacy panics at the compatibility boundary instead of predicting
failure with a separate precondition check.

Co-Authored-By: Warp <agent@warp.dev>
Comment thread crates/warpui_core/src/core/try_update_view_tests.rs Outdated
Comment thread app/src/ai/agent_sdk/driver/terminal_tests.rs Outdated
Comment thread app/src/ai/agent_sdk/driver/terminal.rs Outdated
Comment thread crates/warpui_core/src/core/view/handle.rs Outdated
Comment thread crates/warpui_core/src/core/view/handle.rs Outdated
Comment thread crates/warpui_core/src/core/try_update_view_tests.rs Outdated
Comment thread crates/warpui_core/src/core/try_update_view_tests.rs Outdated
warp-agent-staging Bot and others added 3 commits September 1, 2026 19:36
Remove the closed-window terminal driver test, the should-panic update
tests, the call-site comment, and the over-explaining try_update docs.
Keep the behavioral try_update coverage for success, WindowClosed, and
CircularUpdate.
Delete the closed-window driver regression test and the two legacy
panic assertions. Remove the call-site narration around report_if_error
and the try_* docstring that restated a well-known convention. Reflow
the remaining try_update why-comment to 100 columns.

Co-Authored-By: Warp <agent@warp.dev>
@acarl005
acarl005 merged commit 97037ec into master Sep 1, 2026
32 checks passed
@acarl005
acarl005 deleted the factory/guard-closed-retention-view branch September 1, 2026 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants