From 3ed687d1477c468aabe1639c210264bf52aad5cc Mon Sep 17 00:00:00 2001 From: Bennet Bo Fenner Date: Tue, 31 Mar 2026 19:18:15 +0200 Subject: [PATCH] sidebar: Fix double borrow on startup (#52834) ``` thread 'main' (35618165) panicked at crates/gpui/src/app/entity_map.rs:164:32: cannot read workspace::multi_workspace::MultiWorkspace while it is already being updated stack backtrace: 0: __rustc::rust_begin_unwind at /rustc/e408947bfd200af42db322daf0fadfe7e26d3bd1/library/std/src/panicking.rs:689:5 1: core::panicking::panic_fmt at /rustc/e408947bfd200af42db322daf0fadfe7e26d3bd1/library/core/src/panicking.rs:80:14 2: gpui::app::entity_map::double_lease_panic:: at ./crates/gpui/src/app/entity_map.rs:208:5 3: ::read::::{closure#1} at ./crates/gpui/src/app/entity_map.rs:164:32 4: >::unwrap_or_else::<::read::{closure#1}> at /Users/bebo/.rustup/toolchains/1.94.1-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:1067:21 5: ::read:: at ./crates/gpui/src/app/entity_map.rs:164:14 6: >::read at ./crates/gpui/src/app/entity_map.rs:465:21 7: ::show_archive::{closure#0} at ./crates/sidebar/src/sidebar.rs:3462:15 8: >>::and_then::, ::show_archive::{closure#0}> at /Users/bebo/.rustup/toolchains/1.94.1-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:1546:24 9: ::show_archive at ./crates/sidebar/src/sidebar.rs:3461:69 10: ::restore_serialized_state at ./crates/sidebar/src/sidebar.rs:3606:22 11: as workspace::multi_workspace::SidebarHandle>::restore_serialized_state::{closure#0} at ./crates/workspace/src/multi_workspace.rs:216:18 12: ::update_entity:: as workspace::multi_workspace::SidebarHandle>::restore_serialized_state::{closure#0}>::{closure#0} at ./crates/gpui/src/app.rs:2397:26 13: ::update::<(), ::update_entity as workspace::multi_workspace::SidebarHandle>::restore_serialized_state::{closure#0}>::{closure#0}> at ./crates/gpui/src/app.rs:886:22 14: ::update_entity:: as workspace::multi_workspace::SidebarHandle>::restore_serialized_state::{closure#0}> at ./crates/gpui/src/app.rs:2395:14 15: >::update::<(), gpui::app::App, as workspace::multi_workspace::SidebarHandle>::restore_serialized_state::{closure#0}> at ./crates/gpui/src/app/entity_map.rs:481:12 16: as workspace::multi_workspace::SidebarHandle>::restore_serialized_state at ./crates/workspace/src/multi_workspace.rs:215:14 17: workspace::restore_multiworkspace::{closure#0}::{closure#7} at ./crates/workspace/src/workspace.rs:8712:29 18: >::update::::{closure#0}::{closure#1} at ./crates/gpui/src/window.rs:5318:43 19: ::update_entity::>::update::{closure#0}::{closure#1}>::{closure#0} at ./crates/gpui/src/app.rs:2397:26 20: ::update::<(), ::update_entity>::update::{closure#0}::{closure#1}>::{closure#0}> at ./crates/gpui/src/app.rs:886:22 21: ::update_entity::>::update::{closure#0}::{closure#1}> at ./crates/gpui/src/app.rs:2395:14 22: >::update::<(), gpui::app::App, >::update::{closure#0}::{closure#1}> at ./crates/gpui/src/app/entity_map.rs:481:12 23: >::update::::{closure#0} at ./crates/gpui/src/window.rs:5318:21 24: ::update_window_id::, >::update::{closure#0}>::{closure#0} at ./crates/gpui/src/app.rs:1561:26 25: ::update::>, ::update_window_id, >::update::{closure#0}>::{closure#0}> at ./crates/gpui/src/app.rs:886:22 26: ::update_window_id::, >::update::{closure#0}> at ./crates/gpui/src/app.rs:1555:14 27: ::update_window::, >::update::{closure#0}> at ./crates/gpui/src/app.rs:2425:14 28: ::update_window::, >::update::{closure#0}> at ./crates/gpui/src/app/async_context.rs:94:14 29: >::update:: at ./crates/gpui/src/window.rs:5313:12 30: workspace::restore_multiworkspace::{closure#0} at ./crates/workspace/src/workspace.rs:8710:14 31: zed::restore_or_create_workspace::{closure#0} at ./crates/zed/src/main.rs:1358:82 32: zed::main::{closure#10}::{closure#16}::{closure#0}:: at ./crates/zed/src/main.rs:877:84 33: ::spawn::::{closure#0} at ./crates/gpui/src/app.rs:1633:44 34: >> as core::future::future::Future>::poll at /Users/bebo/.rustup/toolchains/1.94.1-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/future/future.rs:133:9 35: >> as core::future::future::Future>::poll at /Users/bebo/.rustup/toolchains/1.94.1-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/future/future.rs:133:9 36: >>> as core::future::future::Future>::poll at ./crates/scheduler/src/executor.rs:361:64 37: >>>, (), ::spawn>>>::{closure#0}, scheduler::RunnableMeta>>::run at /Users/bebo/.cargo/git/checkouts/async-task-e468f817236eac43/b4486cd/src/raw.rs:296:17 38: >::run at /Users/bebo/.cargo/git/checkouts/async-task-e468f817236eac43/b4486cd/src/runnable.rs:788:18 39: gpui_macos::dispatcher::trampoline at ./crates/gpui_macos/src/dispatcher.rs:197:14 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: <() as objc::message::MessageArguments>::invoke::<()> at /Users/bebo/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/objc-0.2.7/src/message/mod.rs:128:17 54: objc::message::platform::send_unverified:: at /Users/bebo/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/objc-0.2.7/src/message/apple/mod.rs:27:9 55: objc::message::send_message:: at /Users/bebo/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/objc-0.2.7/src/message/mod.rs:178:5 56: <*mut objc::runtime::Object as cocoa::appkit::NSApplication>::run at /Users/bebo/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/cocoa-0.26.0/src/appkit.rs:628:9 57: ::run at ./crates/gpui_macos/src/platform.rs:488:17 58: ::run:: at ./crates/gpui/src/app.rs:187:18 59: zed::main at ./crates/zed/src/main.rs:456:9 60: >::call_once at /Users/bebo/.rustup/toolchains/1.94.1-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5 note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace ``` Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - N/A --- crates/sidebar/src/sidebar.rs | 4 +++- crates/sidebar/src/sidebar_tests.rs | 35 +++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/crates/sidebar/src/sidebar.rs b/crates/sidebar/src/sidebar.rs index 31c796b200cc84d062cad6f404dd7ec4736453a4..450a2674e0062d917003758c41c445048ee603f7 100644 --- a/crates/sidebar/src/sidebar.rs +++ b/crates/sidebar/src/sidebar.rs @@ -3601,7 +3601,9 @@ impl WorkspaceSidebar for Sidebar { .map(|(s, count)| (PathList::deserialize(&s), count)) .collect(); if serialized.active_view == SerializedSidebarView::Archive { - self.show_archive(window, cx); + cx.defer_in(window, |this, window, cx| { + this.show_archive(window, cx); + }); } } cx.notify(); diff --git a/crates/sidebar/src/sidebar_tests.rs b/crates/sidebar/src/sidebar_tests.rs index 18fa8c9375c8d9c30ca3c1369613c0385f1cc94d..d0400d1ae4338ac5de4dfee0daca9196f12030b5 100644 --- a/crates/sidebar/src/sidebar_tests.rs +++ b/crates/sidebar/src/sidebar_tests.rs @@ -322,6 +322,41 @@ async fn test_serialization_round_trip(cx: &mut TestAppContext) { assert_eq!(expanded1.get(&path_list), Some(&2)); } +#[gpui::test] +async fn test_restore_serialized_archive_view_does_not_panic(cx: &mut TestAppContext) { + // A regression test to ensure that restoring a serialized archive view does not panic. + let project = init_test_project_with_agent_panel("/my-project", cx).await; + let (multi_workspace, cx) = + cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx)); + let (sidebar, _panel) = setup_sidebar_with_agent_panel(&multi_workspace, cx); + cx.update(|_window, cx| { + AgentRegistryStore::init_test_global(cx, vec![]); + }); + + let serialized = serde_json::to_string(&SerializedSidebar { + width: Some(400.0), + collapsed_groups: Vec::new(), + expanded_groups: Vec::new(), + active_view: SerializedSidebarView::Archive, + }) + .expect("serialization should succeed"); + + multi_workspace.update_in(cx, |multi_workspace, window, cx| { + if let Some(sidebar) = multi_workspace.sidebar() { + sidebar.restore_serialized_state(&serialized, window, cx); + } + }); + cx.run_until_parked(); + + // After the deferred `show_archive` runs, the view should be Archive. + sidebar.read_with(cx, |sidebar, _cx| { + assert!( + matches!(sidebar.view, SidebarView::Archive(_)), + "expected sidebar view to be Archive after restore, got ThreadList" + ); + }); +} + #[test] fn test_clean_mention_links() { // Simple mention link