slint-ui/slint · error
removal index (is ) should be < len (is )
Error message
removal index (is {row}) should be < len (is {len}) What it means
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.
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
Example fix
// before
vec.remove(index);
// after
if index < vec.len() {
vec.remove(index);
} Defensive patterns
Strategy: validation
Validate before calling
if row < vec.len() {
vec.remove(row);
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Model implementations removing rows based on UI events while the underlying data was already shrunk; off-by-one loops; concurrent modifications invalidating cached indices.
Related errors
- insertion index (is ) should be <= len (is )
- Length was checked
- a setter belongs to a field
- an identifier
- binding was of the wrong type
AI-assisted analysis of slint-ui/slint@bb937076de (2026-09-16).
Data as JSON: /api/errors/48a3309a585eb107.
Report an issue: GitHub.
Appendix: source
Thrown at internal/core/sharedvector.rs:253
/// Add an element to the array. If the array was shared, this will make a copy of the array.
pub fn push(&mut self, value: T) {
self.detach(capacity_for_grow(self.capacity(), self.len() + 1, core::mem::size_of::<T>()));
// Safety: detach ensures exclusive ownership and sufficient capacity.
unsafe {
let size = (*self.inner.as_ptr()).header.size;
core::ptr::write(data_ptr(self.inner).add(size), value);
(*self.inner.as_ptr()).header.size = size + 1;
}
}
/// Removes the element at the given index from the array and returns it.
/// If the array was shared, this will make a copy of the array.
///
/// Panics if `row` is out of bounds.
pub fn remove(&mut self, row: usize) -> T {
let len = self.len();
if row >= len {
panic!("removal index (is {row}) should be < len (is {len})");
}
self.detach(len);
unsafe {
let data = data_ptr(self.inner);
let value = core::ptr::read(data.add(row));
let size = (*self.inner.as_ptr()).header.size;
core::ptr::copy(data.add(row + 1), data.add(row), size - 1 - row);
(*self.inner.as_ptr()).header.size = size - 1;
value
}
}
/// Inserts the element at the given index in the array, shifting the following elements.
/// If the array was shared, this will make a copy of the array.
///
/// Panics if `row > len`.
pub fn insert(&mut self, row: usize, value: T) {
let len = self.len();View on GitHub (pinned to bb937076de)