FyroxEngine/Fyrox · error

The handle must be valid!

Error message

The handle must be valid!

What it means

The Index trait implementation for Pool makes pool[handle] syntax return the payload directly. Because indexing must return a reference (not a Result), an invalid or dangling handle causes a panic instead of a recoverable error; the safe alternative is try_get.

Solutions

  1. Use pool.try_get(handle) or graph.try_get_node(handle) and handle None
  2. Check handle != Handle::NONE before indexing
  3. Re-validate stored handles each frame / after deletions instead of caching validity

Example fix

// before
let node = graph[node_handle]; // panics if freed

// after
if let Some(node) = graph.try_get_node(node_handle) {
    // use node
}
Defensive patterns

Strategy: type-guard

Validate before calling

if handle == Handle::NONE || pool.try_get(handle).is_none() { /* skip */ }

Type guard

fn is_alive<T>(pool: &Pool<T>, h: Handle<T>) -> bool { h != Handle::NONE && pool.try_get(h).is_some() }

Try / catch

// prefer try_get over Index entirely; panics here are not meant to be caught
if let Some(v) = pool.try_get(h) { /* use v */ }

Prevention

When it happens

Trigger: Indexing a Pool with Handle::NONE, an expired/freed handle (object removed so generation changed), or a handle from a different pool.

Common situations: Storing handles to scene nodes/widgets and using them after the object was deleted (e.g. node removed from graph but still referenced by a script or UI callback); default/zero handles used unchecked.

Related errors


AI-assisted analysis of FyroxEngine/Fyrox@76c91aad8e (2026-09-10). Data as JSON: /api/errors/c6f335e07e215ec9. Report an issue: GitHub.

Appendix: source

Thrown at fyrox-core/src/pool/mod.rs:1441

            upper_bound.map(|b| u32::try_from(b).expect("upper_bound overflowed u32"));
        let mut pool = Self::with_capacity(upper_bound.unwrap_or(lower_bound));
        for v in iter {
            let _ = pool.spawn(v);
        }
        pool
    }
}

impl<T, U, Container> Index<Handle<U>> for Pool<T, Container>
where
    T: 'static,
    U: ObjectOrVariant<T>,
    Container: PayloadContainer<Element = T> + 'static,
{
    type Output = U;
    #[inline]
    fn index(&self, index: Handle<U>) -> &Self::Output {
        self.try_get(index).expect("The handle must be valid!")
    }
}

impl<T, U, Container> IndexMut<Handle<U>> for Pool<T, Container>
where
    T: 'static,
    U: ObjectOrVariant<T>,
    Container: PayloadContainer<Element = T> + 'static,
{
    #[inline]
    fn index_mut(&mut self, index: Handle<U>) -> &mut Self::Output {
        self.try_get_mut(index).expect("The handle must be valid!")
    }
}

impl<'a, T, P> IntoIterator for &'a Pool<T, P>
where
    P: PayloadContainer<Element = T> + 'static,

View on GitHub (pinned to 76c91aad8e)