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

  1. Return Err from AsyncApp methods when the weak upgrade fails instead of panicking, letting tasks exit gracefully
  2. Ensure tasks are cancelled (not detached) before the App is dropped — track Tasks in the owner or use the executor's shutdown
  3. 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.