{"record":{"id":"f5a3991779d60a67","repo":"zed-industries/zed","slug":"build-entity-is-taken-exactly-once","errorCode":null,"errorMessage":"build_entity is taken exactly once","messagePattern":"build_entity is taken exactly once","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gpui/src/app/async_context.rs","lineNumber":386,"sourceCode":"        self.app\n            .update_window(self.window, |_, window, cx| {\n                window.prompt(level, message, detail, answers, cx)\n            })\n            .unwrap_or_else(|_| oneshot::channel().1)\n    }\n}\n\nimpl AppContext for AsyncWindowContext {\n    fn new<T>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T>\n    where\n        T: 'static,\n    {\n        let mut build_entity = Some(build_entity);\n        match self.app.update_window(self.window, |_, _, cx| {\n            cx.new(\n                build_entity\n                    .take()\n                    .expect(\"build_entity is taken exactly once\"),\n            )\n        }) {\n            Ok(entity) => entity,\n            Err(_) => self.app.new(\n                build_entity\n                    .take()\n                    .expect(\"update_window returned Err without invoking the closure\"),\n            ),\n        }\n    }\n\n    fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {\n        self.app.reserve_entity()\n    }\n\n    fn insert_entity<T: 'static>(\n        &mut self,\n        reservation: Reservation<T>,","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/zed-industries/zed/blob/f4178619acd0d47ea1f76a2025c42962c6d6638c/crates/gpui/src/app/async_context.rs#L368-L404","documentation":"A closure-once invariant in AsyncWindowContext::new: the entity constructor is wrapped in Option::take() inside a closure passed to update_window, and .expect('build_entity is taken exactly once') fires if that closure executes a second time. gpui's update_window must invoke the closure exactly once per call; a second invocation means the window update machinery re-ran the callback — a framework bug or a corrupted window state, never caller input.","triggerScenarios":"Thrown at crates/gpui/src/app/async_context.rs:386 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Replace expect with unwrap_or_else that builds a default entity (or returns an error) so a double call degrades instead of panicking","Document/encapsulate the single-invocation contract on update_window and cover it with a test","Restructure to take the closure before entering update_window so re-invocation is impossible"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"f4178619acd0d47ea1f76a2025c42962c6d6638c","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}