{"record":{"id":"fd3d02506e57edb1","repo":"slint-ui/slint","slug":"the-row-index-is-out-of-bounds-the-model-has-rows","errorCode":null,"errorMessage":"the row index is out of bounds (the model has {} rows)","messagePattern":"the row index is out of bounds \\(the model has (.+?) rows\\)","errorType":"exception","errorClass":"ModelError","httpStatus":null,"severity":"error","filePath":"internal/core/model.rs","lineNumber":31,"sourceCode":"use alloc::vec::Vec;\nuse core::cell::OnceCell;\nuse core::cell::{Cell, RefCell};\nuse core::pin::Pin;\n#[allow(unused)]\nuse euclid::num::{Ceil, Floor};\npub use model_peer::*;\nuse pin_project::pin_project;\n\nmod adapters;\nmod model_peer;\nmod repeater;\n\npub use repeater::{Conditional, ListViewProperties, RepeatedItemTree, Repeater, RepeaterTracker};\n\n/// Error returned by the row mutation functions of [`Model`] when the modification\n/// was not applied.\n#[derive(Debug, Clone, Eq, PartialEq, derive_more::Error, derive_more::Display)]\npub struct ModelError(#[error(not(source))] ErrorImpl);\n\n#[derive(Debug, Clone, Eq, PartialEq, derive_more::Display)]\nenum ErrorImpl {\n    #[display(\"the row index is out of bounds (the model has {_0} rows)\")]\n    OutOfBounds(usize),\n    #[display(\"the model {_0} does not support this modification\")]\n    Unsupported(alloc::borrow::Cow<'static, str>),\n}\n\nimpl ModelError {\n    /// The row index is out of the model's bounds. `row_count` is the model's number of rows.\n    pub fn out_of_bounds(row_count: usize) -> Self {\n        Self(ErrorImpl::OutOfBounds(row_count))\n    }\n\n    /// The model does not support this modification.\n    pub fn unsupported(model: &(impl Model + ?Sized)) -> Self {\n        Self(ErrorImpl::Unsupported(core::any::type_name_of_val(model).into()))","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/slint-ui/slint/blob/3a7e700487dc74d404cad0726378053ab763d4e0/internal/core/model.rs#L13-L49","documentation":"ModelError::OutOfBounds is returned by the Model trait's row mutation functions (set_row_data, insert_rows, remove_rows) when the given row index is not valid for the model's current row count. Models in Slint are the data source behind `for` loops and repeaters; mutating a row that does not exist would corrupt the repeater's bookkeeping, so the operation is refused and the model is left unchanged.","triggerScenarios":"Calling `model.set_row_data(i, ...)` with `i >= model.row_count()`; `insert_rows`/`remove_rows` with a row index greater than the current row count; mutating a model from a stale index captured before another thread or binding shrank the model.","commonSituations":"Race between reading `row_count()` and mutating; off-by-one when appending (using `row_count()` instead of `row_count()` as insert position is fine, but `row_count()+1` is not); removing rows while a UI callback still holds an old index; wrapping a filtered/subset model and using indices from the parent model.","solutions":["Check `model.row_count()` before mutating and clamp/skip when the index is out of range: `if row < model.row_count() { model.set_row_data(row, v); }`.","For insertion, use `model.insert_rows(model.row_count(), 1)` to append at the end rather than an arbitrary index.","Re-fetch indices after any model change (use ModelNotifier/ModelRc change callbacks) instead of caching row positions across mutations."],"exampleFix":"// before\nmodel.set_row_data(index, new_item); // panics-free but returns OutOfBounds\n// after\nif index < model.row_count() {\n    model.set_row_data(index, new_item);\n}","handlingStrategy":"validation","validationCode":"if row >= model.row_count() {\n    return; // or clamp\n}\nmodel.set_row_data(row, value);","typeGuard":"fn valid_row(model: &dyn Model<R>, row: usize) -> bool {\n    row < model.row_count()\n}","tryCatchPattern":"match model.set_row_data(row, value) {\n    Ok(()) => {},\n    Err(ModelError::OutOfBounds(_)) => eprintln!(\"row {row} no longer exists\"),\n}","preventionTips":["Always re-read row_count() immediately before a mutation.","Do not cache row indices across model change notifications.","Use insert_rows(row_count(), n) to append rather than guessing indices.","When wrapping models, translate indices from the inner model to the wrapper."],"tags":["model","index","rust","slint"],"backgroundTag":"index-out-of-bounds","analyzedSha":"3a7e700487dc74d404cad0726378053ab763d4e0","analyzedAt":"2026-09-16T01:37:20.251Z","contentChangedAt":"2026-09-16T01:37:20.251Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}