FyroxEngine/Fyrox · error

Ticket index was invalid

Error message

Ticket index was invalid

What it means

Pool::put_back returns a previously take_reserve'd record to the pool using the ticket taken from take_reserve. The ticket's index must point to a valid pool record; if the ticket is stale, corrupted, duplicated, or belongs to another pool, records_get_mut returns None and the code panics.

Solutions

  1. Only use tickets returned by take_reserve on the same pool, exactly once
  2. Ensure each take_reserve is matched by exactly one put_back (no duplicates)
  3. Verify the pool was not recreated/cleared while the ticket was held

Example fix

// before
pool.put_back(old_ticket, value); // ticket already consumed

// after
let (ticket, _) = pool.take_reserve(handle);
// ... exactly once ...
let handle = pool.put_back(ticket, value);
Defensive patterns

Strategy: type-guard

Validate before calling

// ensure ticket was produced by take_reserve on this pool and not yet consumed
assert!(tickets.contains_key(&ticket.index));

Try / catch

// pre-condition check instead of catch: track live tickets in a set; on drop/put_back remove them exactly once

Prevention

When it happens

Trigger: Calling put_back with a Ticket that was not obtained from take_reserve on this same pool, a ticket used twice (forgotten handles / double put_back), or a ticket from a different pool instance.

Common situations: Undo/redo or frame-delayed reinsertion logic that stores tickets across pool rebuilds; copying ticket values and putting back twice; mixing tickets between pools of the same type.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

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

                };
                Ok((ticket, payload))
            } else {
                Err(PoolError::Empty(handle.into()))
            }
        } else {
            Err(PoolError::InvalidGeneration(handle.generation))
        }
    }

    /// Returns the value back into the pool using the given ticket. See [`take_reserve`] for more
    /// information.
    ///
    /// [`take_reserve`]: Pool::take_reserve
    #[inline]
    pub fn put_back(&mut self, ticket: Ticket<T>, value: T) -> Handle<T> {
        let record = self
            .records_get_mut(ticket.index)
            .expect("Ticket index was invalid");
        let old = record.payload.replace(value);
        assert!(old.is_none());
        let handle = Handle::new(ticket.index, record.generation);
        std::mem::forget(ticket);
        handle
    }

    /// Forgets that value at ticket was reserved and makes it usable again.
    /// Useful when you don't need to put value back by ticket, but just make
    /// pool record usable again.
    #[inline]
    pub fn forget_ticket(&mut self, ticket: Ticket<T>) {
        self.free_stack.push(ticket.index);
        std::mem::forget(ticket);
    }

    /// Returns total capacity of pool. Capacity has nothing about real amount of objects in pool!
    #[inline]

View on GitHub (pinned to 76c91aad8e)