{"record":{"id":"85cd3478252cd842","repo":"zed-industries/zed","slug":"main-thread-message-channel-extension-name-id","errorCode":null,"errorMessage":"main thread message channel, extension {name} (id {id})","messagePattern":"main thread message channel, extension (.+?) \\(id (.+?)\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/extension_host/src/wasm_host.rs","lineNumber":968,"sourceCode":"        let (return_tx, return_rx) = oneshot::channel();\n        self.host\n            .main_thread_message_tx\n            .clone()\n            .unbounded_send(Box::new(move |cx| {\n                async {\n                    let result = f(cx).await;\n                    return_tx.send(result).ok();\n                }\n                .boxed_local()\n            }))\n            .unwrap_or_else(|_| {\n                panic!(\n                    \"main thread message channel should not be closed yet, extension {} (id {})\",\n                    self.manifest.name, self.manifest.id,\n                )\n            });\n        let name = self.manifest.name.clone();\n        let id = self.manifest.id.clone();\n        async move {\n            return_rx.await.unwrap_or_else(|_| {\n                panic!(\"main thread message channel, extension {name} (id {id})\")\n            })\n        }\n    }\n\n    fn work_dir(&self) -> PathBuf {\n        self.host.work_dir.join(self.manifest.id.as_ref())\n    }\n\n    fn extension_error(&self, message: String) -> anyhow::Error {\n        anyhow!(\n            \"from extension \\\"{}\\\" version {}: {}\",\n            self.manifest.name,\n            self.manifest.version,\n            message\n        )","sourceCodeStart":950,"sourceCodeEnd":986,"githubUrl":"https://github.com/zed-industries/zed/blob/5a9b9558db01a6b906cec2fb70a797affdc58cdd/crates/extension_host/src/wasm_host.rs#L950-L986","documentation":"The return half of the extension main-thread handshake: after posting work, the extension awaits a oneshot receiver for the result. If the main thread dropped the closure without sending a reply (the app quit mid-call), the oneshot sender is destroyed, `await` errors, and the extension panics with the extension name and id.","triggerScenarios":"App shutdown occurring while an extension is awaiting the result of a main-thread API call — the posted closure never runs, so no result is ever sent.","commonSituations":"Quitting Zed while an extension has an in-flight command or API request; races during rapid window close; extension tasks that outlive deactivate.","solutions":["Update Zed — the host should stop dispatching extension work before dropping the main-thread channel; such races are fixed upstream","Extension authors: make deactivate cancel in-flight tasks so nothing is left awaiting main-thread replies during quit","Report with the extension name/id from the message and the exact quit sequence that triggers it"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Make deactivate cancel tasks awaiting main-thread results so quit cannot strand them","Avoid fire-and-forget API calls right before app exit","Report reproducible 'quit while extension active' sequences with the extension name/id from the message"],"tags":["zed","extension-host","wasm","oneshot","shutdown","panic"],"backgroundTag":"receive-on-closed-channel","analyzedSha":"5a9b9558db01a6b906cec2fb70a797affdc58cdd","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}