{"record":{"id":"738eb80e8d82a728","repo":"FyroxEngine/Fyrox","slug":"attempt-to-replace-object-in-pool-using-dangling-h","errorCode":null,"errorMessage":"Attempt to replace object in pool using dangling handle! Handle is {:?}, but pool record has {} generation","messagePattern":"Attempt to replace object in pool using dangling handle! Handle is (.+?), but pool record has (.+?) generation","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"fyrox-core/src/pool/mod.rs","lineNumber":1203,"sourceCode":"    ///\n    /// [`take_reserve`]: Pool::take_reserve\n    /// [`alive_count`]: Pool::alive_count\n    #[inline]\n    pub fn total_count(&self) -> u32 {\n        let free = u32::try_from(self.free_stack.len()).expect(\"free stack length overflowed u32\");\n        self.records_len() - free\n    }\n\n    #[inline]\n    pub fn replace(&mut self, handle: Handle<T>, payload: T) -> Option<T> {\n        let index_usize = usize::try_from(handle.index).expect(\"index overflowed usize\");\n        if let Some(record) = self.records.get_mut(index_usize) {\n            if record.generation == handle.generation {\n                self.free_stack.retain(|i| *i != handle.index);\n\n                record.payload.replace(payload)\n            } else {\n                panic!(\"Attempt to replace object in pool using dangling handle! Handle is {:?}, but pool record has {} generation\", handle, record.generation);\n            }\n        } else {\n            None\n        }\n    }\n\n    /// Returns a reference to the first element in the pool (if any).\n    pub fn first_ref(&self) -> Option<&T> {\n        self.iter().next()\n    }\n\n    /// Returns a reference to the first element in the pool (if any).\n    pub fn first_mut(&mut self) -> Option<&mut T> {\n        self.iter_mut().next()\n    }\n\n    /// Checks if given handle \"points\" to some object.\n    ///","sourceCodeStart":1185,"sourceCodeEnd":1221,"githubUrl":"https://github.com/FyroxEngine/Fyrox/blob/76c91aad8eca488ce527b1af707be8b3b24ad72d/fyrox-core/src/pool/mod.rs#L1185-L1221","documentation":"Pool's replace-by-handle checks that the handle's generation matches the record's generation before overwriting. A generation mismatch means the handle is dangling — the object at that index was freed and the slot possibly reused — so replacing would silently write into someone else's object. The pool panics instead of corrupting data.","triggerScenarios":"Calling Pool::replace (or the method at fyrox-core/src/pool/mod.rs:1203) with a Handle obtained before the target was freed and its slot recycled; also after wrapping/free of the original object.","commonSituations":"Storing handles long-term (in components, UI, scripts) while the referenced pool object is freed and the index reused; event callbacks firing after the target was destroyed.","solutions":["Validate the handle with pool.is_valid_handle(handle) (or try_contains) before replacing.","Re-fetch a fresh handle after any free/spawn sequence touching the same pool.","Subscribe to destruction events and clear stored handles when their target is freed."],"exampleFix":"// before\npool.replace(stale_handle, new_obj); // panics on generation mismatch\n// after\nif pool.is_valid_handle(stale_handle) {\n    pool.replace(stale_handle, new_obj);\n} else {\n    let h = pool.spawn(new_obj);\n}","handlingStrategy":"validation","validationCode":"// validate before replace\nif !pool.is_valid_handle(handle) {\n    // handle is dangling: re-fetch or respawn\n}","typeGuard":"fn is_live<T>(pool: &Pool<T>, h: Handle<T>) -> bool {\n    pool.try_borrow(h).is_some()\n}","tryCatchPattern":null,"preventionTips":["Check is_valid_handle/try_borrow before every replace on long-lived handles.","Clear stored handles on destruction events from the pool/graph.","Treat handles as generation-checked capabilities; never cache raw indices."],"tags":["pool","handle","dangling","generation","panic"],"backgroundTag":"entity-not-found","analyzedSha":"76c91aad8eca488ce527b1af707be8b3b24ad72d","analyzedAt":"2026-09-10T16:04:01.633Z","contentChangedAt":"2026-09-10T16:04:01.633Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}