FyroxEngine/Fyrox · critical
Animation pool must be empty on load!
Error message
Animation pool must be empty on load!
What it means
AnimationContainer's Visit impl panics during deserialization when the animation pool already holds objects. Loading (reading) a container assumes it was freshly constructed with an empty pool; deserializing into a container with existing animations would append/mix pool records and corrupt indices. The library therefore enforces that the pool has zero capacity before read-mode visiting begins.
Solutions
- Deserialize into a freshly constructed AnimationContainer (AnimationContainer::new()) instead of a reused one.
- If reloading, drop the old container (or clear its pool) before starting the visit.
- Check that custom save/load code does not pass a container that was already populated from a scene load.
Example fix
// before
let mut animations = scene.animations_mut(); // already populated
animations.visit("Animations", &mut visitor)?;
// after
let mut animations = AnimationContainer::new(); // empty pool on load
animations.visit("Animations", &mut visitor)?;
*scene.animations_mut() = animations; Defensive patterns
Strategy: validation
Validate before calling
// fyrox (Rust) - ensure container is empty before loading assert!(container.pool.get_capacity() == 0, "pool must be empty before read-visit");
Try / catch
// panics are not catchable in Rust safely; prevent instead: let container = AnimationContainer::new(); // always load into fresh container
Prevention
- Always deserialize into a newly constructed AnimationContainer.
- Never reuse containers across loads/reloads without recreating them.
- Swap the loaded container into the scene after visiting completes.
When it happens
Trigger: Calling Visitor::read/load into an AnimationContainer whose internal pool has non-zero capacity, e.g. reusing an already-populated container as the deserialization target, or calling load twice on the same container.
Common situations: Reusing a scene/animation container across level reloads without recreating it; deserializing saved state into a live container that still contains animations from a previous session.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- An object at index must be returned to a pool it was taken…
- Attempt to spawn an object at pool record with payload!…
- Attempt to replace object in pool using dangling handle!…
- Graph pool must be empty on load!
- Registering empty path.
AI-assisted analysis of FyroxEngine/Fyrox@76c91aad8e (2026-09-10).
Data as JSON: /api/errors/169868a7049c85c1.
Report an issue: GitHub.
Appendix: source
Thrown at fyrox-animation/src/lib.rs:1113
/// Removes queued animation events from every animation in the container.
///
/// # Potential use cases
///
/// Sometimes there is a need to use animation events only from one frame, in this case you should clear events each frame.
/// This situation might come up when you have multiple animations with signals, but at each frame not every event gets
/// processed. This might result in unwanted side effects, like multiple attack events may result in huge damage in a single
/// frame.
pub fn clear_animation_events(&mut self) {
for animation in self.pool.iter_mut() {
animation.events.clear();
}
}
}
impl<T: EntityId> Visit for AnimationContainer<T> {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
if visitor.is_reading() && self.pool.get_capacity() != 0 {
panic!("Animation pool must be empty on load!");
}
let mut region = visitor.enter_region(name)?;
self.pool.visit("Pool", &mut region)?;
Ok(())
}
}
impl<T: EntityId> Index<Handle<Animation<T>>> for AnimationContainer<T> {
type Output = Animation<T>;
fn index(&self, index: Handle<Animation<T>>) -> &Self::Output {
&self.pool[index]
}
}
View on GitHub (pinned to 76c91aad8e)