leptos-rs/leptos · error
could not find key for index
Error message
could not find key for index {index:?} at {caller} What it means
reactive_stores keys each store field's list indices with per-index keys so fine-grained reactivity can track items across moves. get_trigger_unkeyed walks a field path and, when a parent is keyed, expects a key registered for every index segment; if the key map has no entry for (path, index) it panics. This means the store's internal key bookkeeping is out of sync with the path being resolved.
Solutions
- Access keyed list fields consistently — do not mix keyed (.keys()/.at()) and unkeyed (.with_unkeyed()) resolution on the same path.
- Ensure reads happen while the store is in a consistent state; avoid reading store fields during mutation from another thread/task.
- Recreate or re-sync the store/field if you constructed ArcField paths manually; let the store derive keys itself.
- Upgrade leptos/reactive_stores — this is internal bookkeeping, so a fixed version may resolve the desync.
Defensive patterns
Strategy: validation
Validate before calling
// check index is within the keyed list before resolving an unkeyed path
if index < store.len() && store.keys_contains_index(path, index) { /* resolve */ } Try / catch
std::panic::catch_unwind(|| field.get_trigger_unkeyed(path, segment, caller)).err().map(|_| default_trigger)
Prevention
- Do not mix keyed and unkeyed access to the same store field path.
- Keep reactive_stores updated to the latest patch version.
- Avoid reading store triggers concurrently with structural mutations.
When it happens
Trigger: Resolving an ArcField/field path into an unkeyed store whose parent field is keyed, when the index was never registered — e.g. mixing keyed and unkeyed access to the same store field, or accessing a list index before the store registered its keys (concurrent access during resize/clear).
Common situations: Using .at(index) or keyed list fields on a store while also accessing the same path unkeyed; rapid mutation (splice/clear) racing with a render pass reading triggers for old indices; custom store field code (ArcField) built against paths the store never keyed.
Related errors
- At , you call `to_server_error()` or use `server_fn_error!`…
- should not be used with nested routes.
- internal error: entered unreachable code
- internal error: entered unreachable code
- internal error: entered unreachable code
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/6cf1fddb26e6fc46.
Report an issue: GitHub.
Appendix: source
Thrown at reactive_stores/src/store_field.rs:153
let trigger = triggers.write().or_poisoned().get_or_insert(path);
trigger
}
#[track_caller]
fn get_trigger_unkeyed(&self, path: StorePath) -> StoreFieldTrigger {
let caller = std::panic::Location::caller();
let orig_path = path.clone();
let mut path = StorePath::with_capacity(orig_path.len());
for segment in &orig_path {
let parent_is_keyed = self.keys.contains_key(&path);
if parent_is_keyed {
let key = self
.keys
.get_key_for_index(&(path.clone(), segment.0))
.unwrap_or_else(|| {
panic!(
"could not find key for index {:?} at {}",
(path.clone(), segment.0),
caller
)
});
path.push(key);
} else {
path.push(*segment);
}
}
self.get_trigger(path)
}
#[track_caller]
fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
iter::empty()
}
View on GitHub (pinned to 32d20f6c9d)