leptos-rs/leptos · error

could not find key for index {index:?} at {caller}

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.

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)

Solutions

  1. Access keyed list fields consistently — do not mix keyed (.keys()/.at()) and unkeyed (.with_unkeyed()) resolution on the same path.
  2. Ensure reads happen while the store is in a consistent state; avoid reading store fields during mutation from another thread/task.
  3. Recreate or re-sync the store/field if you constructed ArcField paths manually; let the store derive keys itself.
  4. 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

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


AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01). Data as JSON: /api/errors/6cf1fddb26e6fc46. Report an issue: GitHub.