zed-industries/zed · error
app was released before async operation completed
Error message
app was released before async operation completed
What it means
A lifetime guard on AsyncApp: it holds only a Weak reference to the AppCell, and upgrading fails (panicking with 'app was released before async operation completed') when a foreground task resumes after the App was dropped. In a normal application lifecycle the executor shuts down before the app is freed so this cannot fire; it occurs when AsyncApp/AsyncWindowContext is held beyond app teardown — e.g. a detached task or test harness outliving the App.
Source
Thrown at crates/gpui/src/app/async_context.rs:32
/// An async-friendly version of [App] with a static lifetime so it can be held across `await` points in async code.
/// You're provided with an instance when calling [App::spawn], and you can also create one with [App::to_async].
///
/// Internally, this holds a weak reference to an `App`. Methods will panic if the app has been dropped,
/// but this should not happen in practice when using foreground tasks spawned via `cx.spawn()`,
/// as the executor checks if the app is alive before running each task.
#[derive(Clone)]
pub struct AsyncApp {
pub(crate) app: Weak<AppCell>,
pub(crate) background_executor: BackgroundExecutor,
pub(crate) foreground_executor: ForegroundExecutor,
}
impl AsyncApp {
fn app(&self) -> std::rc::Rc<AppCell> {
self.app
.upgrade()
.expect("app was released before async operation completed")
}
}
impl AppContext for AsyncApp {
fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
let app = self.app();
let mut app = app.borrow_mut();
app.new(build_entity)
}
fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
let app = self.app();
let mut app = app.borrow_mut();
app.reserve_entity()
}
fn insert_entity<T: 'static>(
&mut self,View on GitHub (pinned to f4178619ac)
Solutions
- Return Err from AsyncApp methods when the weak upgrade fails instead of panicking, letting tasks exit gracefully
- Ensure tasks are cancelled (not detached) before the App is dropped — track Tasks in the owner or use the executor's shutdown
- In tests, keep the TestAppContext alive until all spawned tasks complete
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at crates/gpui/src/app/async_context.rs:32 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/6c72b178cf336572.
Report an issue: GitHub.