{"record":{"id":"037fdb94dfb0208a","repo":"zed-industries/zed","slug":"leases-must-be-ended-with-entitymap-end-lease","errorCode":null,"errorMessage":"Leases must be ended with EntityMap::end_lease","messagePattern":"Leases must be ended with EntityMap::end_lease","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gpui/src/app/entity_map.rs","lineNumber":258,"sourceCode":"\nimpl<T: 'static> core::ops::Deref for Lease<T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        self.inner.entity.as_ref().unwrap().downcast_ref().unwrap()\n    }\n}\n\nimpl<T: 'static> core::ops::DerefMut for Lease<T> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        self.inner.entity.as_mut().unwrap().downcast_mut().unwrap()\n    }\n}\n\nimpl Drop for LeaseInner {\n    fn drop(&mut self) {\n        if self.entity.is_some() && !panicking() {\n            panic!(\"Leases must be ended with EntityMap::end_lease\")\n        }\n    }\n}\n\n#[derive(Deref, DerefMut)]\npub(crate) struct Slot<T>(Entity<T>);\n\n/// A dynamically typed reference to a entity, which can be downcast into a `Entity<T>`.\npub struct AnyEntity {\n    pub(crate) entity_id: EntityId,\n    pub(crate) entity_type: TypeId,\n    entity_map: Weak<RwLock<EntityRefCounts>>,\n    #[cfg(any(test, feature = \"leak-detection\"))]\n    handle_id: HandleId,\n}\n\nimpl AnyEntity {\n    fn new(","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/zed-industries/zed/blob/916fc2b8cb3a815cbef4a3b40e13081be72036b6/crates/gpui/src/app/entity_map.rs#L240-L276","documentation":"`Lease` guards an exclusive borrow of an entity slot in GPUI's EntityMap. A lease must be returned via `EntityMap::end_lease`, which marks the entity as updatable again and clears the slot from the guard. If a `LeaseInner` is dropped while the entity is still present (i.e. the lease was never properly ended), the Drop impl panics so the bug is caught instead of silently corrupting the map. During panic unwinding (`panicking()`) the check is suppressed to avoid double panics.","triggerScenarios":"A `Lease`/`LeaseInner` is dropped without having gone through `EntityMap::end_lease` — e.g. a lease extracted/erased from the map is leaked or its guard dropped manually instead of being returned through the owning map.","commonSituations":"Custom code holding onto `Lease` handles past the update call, early returns/`?` inside wrappers that bypass `end_lease`, or misuse of internal APIs in tests that construct leases directly.","solutions":["Ensure every lease is returned through `EntityMap::end_lease` (typically done for you by `entity.update(...)`).","Do not hold `Lease` values across early returns; use the public `Entity::update`/`read` APIs instead of manipulating leases directly.","If you see this in a panic report, inspect the backtrace to find the code path that dropped the lease without cleanup and route it through the map's end_lease."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// public API alternative: never touch Lease directly\nentity.update(cx, |this, cx| { /* work */ }); // end_lease handled by EntityMap","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use Entity::update/read instead of constructing or holding Lease values yourself.","Avoid early returns (`?`) inside wrappers that bypass end_lease cleanup.","Treat Lease as an internal type; if you must use it, always route removal through EntityMap::end_lease."],"tags":["panic","drop","lease","entity-map","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"916fc2b8cb3a815cbef4a3b40e13081be72036b6","analyzedAt":"2026-09-19T19:09:50.599Z","contentChangedAt":"2026-09-19T19:09:50.599Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}