{"record":{"id":"48a3309a585eb107","repo":"slint-ui/slint","slug":"removal-index-is-row-should-be-len-is-len","errorCode":null,"errorMessage":"removal index (is {row}) should be < len (is {len})","messagePattern":"removal index \\(is (.+?)\\) should be < len \\(is (.+?)\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/core/sharedvector.rs","lineNumber":253,"sourceCode":"    /// Add an element to the array. If the array was shared, this will make a copy of the array.\n    pub fn push(&mut self, value: T) {\n        self.detach(capacity_for_grow(self.capacity(), self.len() + 1, core::mem::size_of::<T>()));\n        // Safety: detach ensures exclusive ownership and sufficient capacity.\n        unsafe {\n            let size = (*self.inner.as_ptr()).header.size;\n            core::ptr::write(data_ptr(self.inner).add(size), value);\n            (*self.inner.as_ptr()).header.size = size + 1;\n        }\n    }\n\n    /// Removes the element at the given index from the array and returns it.\n    /// If the array was shared, this will make a copy of the array.\n    ///\n    /// Panics if `row` is out of bounds.\n    pub fn remove(&mut self, row: usize) -> T {\n        let len = self.len();\n        if row >= len {\n            panic!(\"removal index (is {row}) should be < len (is {len})\");\n        }\n        self.detach(len);\n        unsafe {\n            let data = data_ptr(self.inner);\n            let value = core::ptr::read(data.add(row));\n            let size = (*self.inner.as_ptr()).header.size;\n            core::ptr::copy(data.add(row + 1), data.add(row), size - 1 - row);\n            (*self.inner.as_ptr()).header.size = size - 1;\n            value\n        }\n    }\n\n    /// Inserts the element at the given index in the array, shifting the following elements.\n    /// If the array was shared, this will make a copy of the array.\n    ///\n    /// Panics if `row > len`.\n    pub fn insert(&mut self, row: usize, value: T) {\n        let len = self.len();","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/slint-ui/slint/blob/bb937076de3f7919766c1f25e2e969367cf77e9a/internal/core/sharedvector.rs#L235-L271","documentation":"SharedVector::remove panics when the requested removal index is >= the vector's current length. The guard exists before detaching and shifting elements so an out-of-bounds read/write via unsafe pointers never happens. Mirrors Vec::remove's panic semantics.","triggerScenarios":"Calling `vec.remove(row)` where row >= vec.len() — e.g. removing from an empty SharedVector, removing with a stale index after prior removals shrunk the vector, or an index derived from a model row count mismatch.","commonSituations":"Model implementations removing rows based on UI events while the underlying data was already shrunk; off-by-one loops; concurrent modifications invalidating cached indices.","solutions":["Check `if row < vec.len()` before calling remove","Use `vec.get(row)` or a bounds-checked branch to validate the index comes from a current row count","If implementing a Model, verify row indices against the current row_count() inside the removal callback"],"exampleFix":"// before\nvec.remove(index);\n// after\nif index < vec.len() {\n    vec.remove(index);\n}","handlingStrategy":"validation","validationCode":"if row < vec.len() {\n    vec.remove(row);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Re-read len() right before index-based mutations","Avoid caching row indices across mutations","In Model impls, validate row against row_count() in every row-indexed method"],"tags":["rust","panic","bounds-check","vector"],"backgroundTag":"index-out-of-bounds","analyzedSha":"bb937076de3f7919766c1f25e2e969367cf77e9a","analyzedAt":"2026-09-16T01:37:20.251Z","contentChangedAt":"2026-09-16T01:37:20.251Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}