zed-industries/zed · error
main thread message channel should not be closed yet, extens
Error message
main thread message channel should not be closed yet, extension {} (id {}) What it means
WasmHost::run_on_main_thread posts a closure to the main thread over an unbounded channel. Sending can only fail once the receiving end has been dropped — i.e. the application is tearing down. The code asserts extensions cannot be running at that point and panics, naming the extension and its id.
Source
Thrown at crates/extension_host/src/wasm_host.rs:959
}
}
impl WasmState {
fn on_main_thread<T, Fn>(&self, f: Fn) -> impl 'static + Future<Output = T>
where
T: 'static + Send,
Fn: 'static + Send + for<'a> FnOnce(&'a mut AsyncApp) -> LocalBoxFuture<'a, T>,
{
let (return_tx, return_rx) = oneshot::channel();
self.host
.main_thread_message_tx
.clone()
.unbounded_send(Box::new(move |cx| {
async {
let result = f(cx).await;
return_tx.send(result).ok();
}
.boxed_local()
}))
.unwrap_or_else(|_| {
panic!(
"main thread message channel should not be closed yet, extension {} (id {})",
self.manifest.name, self.manifest.id,
)
});
let name = self.manifest.name.clone();
let id = self.manifest.id.clone();
async move {
return_rx.await.unwrap_or_else(|_| {
panic!("main thread message channel, extension {name} (id {id})")
})
}
}
fn work_dir(&self) -> PathBuf {
self.host.work_dir.join(self.manifest.id.as_ref())View on GitHub (pinned to 5a9b9558db)
Solutions
- Update Zed — shutdown-ordering fixes in extension_host land regularly and this class of panic is treated as a bug
- As an extension author, cancel timers/requests in deactivate and never start new API calls after deactivation
- Report the panic with the extension name/id shown in the message and repro steps (usually 'quit while extension X was active')
Defensive patterns
Strategy: fallback
Prevention
- Extension authors: cancel timers and in-flight requests in deactivate; start no new API calls afterwards
- Keep extension background work short-lived so it rarely straddles app quit
- Update Zed regularly: shutdown ordering between extension_host and the main loop is actively hardened
When it happens
Trigger: An extension invokes an API that proxies to the main thread (most extension host APIs do) during or after app shutdown, after the main-thread message loop was dropped but before the extension was fully deactivated.
Common situations: Long-running extension tasks (timers, background HTTP requests) completing just as the window/app quits; shutdown-ordering races between the extension host and GPUI's main loop.
Related errors
- main thread message channel, extension {name} (id {id})
- blocking sender returned without value
- row out of range
- invalid display row {}
- anchor's path was never added to multibuffer
AI-assisted analysis of zed-industries/zed@5a9b9558db (2026-08-20).
Data as JSON: /api/errors/a94cb711338ef7b3.
Report an issue: GitHub.