bevyengine/bevy · error

it is not valid to call sort() after next()

Error message

it is not valid to call sort() after next()

What it means

Panic from QueryIter::sort_impl: the iterator has already been partially consumed by next() (its iteration cursor set archetype/table entity slices), so the backing storage can no longer be safely sorted in place. Sorting is only valid on a fresh, unconsumed QueryIter over a non-empty query.

Source

Thrown at crates/bevy_ecs/src/query/iter.rs:1011

    /// # Panics
    ///
    /// This will panic if `next` has been called on `QueryIter` before, unless the underlying `Query` is empty.
    fn sort_impl<L: ReadOnlyQueryData + SingleEntityQueryData + 'w>(
        self,
        f: impl FnOnce(&mut Vec<(L::Item<'_, '_>, NeutralOrd<Entity>)>),
    ) -> QuerySortedIter<
        'w,
        's,
        D,
        F,
        impl ExactSizeIterator<Item = Entity> + DoubleEndedIterator + FusedIterator + 'w,
    > {
        // On the first successful iteration of `QueryIterationCursor`, `archetype_entities` or `table_entities`
        // will be set to a non-zero value. The correctness of this method relies on this.
        // I.e. this sort method will execute if and only if `next` on `QueryIterationCursor` of a
        // non-empty `QueryIter` has not yet been called. When empty, this sort method will not panic.
        if !self.cursor.archetype_entities.is_empty() || !self.cursor.table_entities.is_empty() {
            panic!("it is not valid to call sort() after next()")
        }

        let world = self.world;

        let query_lens_state = self.query_state.transmute_filtered::<(L, Entity), F>(world);

        // SAFETY:
        // `self.world` has permission to access the required components.
        // The original query iter has not been iterated on, so no items are aliased from it.
        // `QueryIter::new` ensures `world` is the same one used to initialize `query_state`.
        let query_lens = unsafe { query_lens_state.query_unchecked_manual(world) }.into_iter();
        let mut keyed_query: Vec<_> = query_lens
            .map(|(key, entity)| (key, NeutralOrd(entity)))
            .collect();
        f(&mut keyed_query);
        let entity_iter = keyed_query
            .into_iter()
            .map(|(.., entity)| entity.0)

View on GitHub (pinned to 396ca72708)

Solutions

  1. Call sort()/sort_by_key() before any next() on the iterator
  2. Use a fresh Query for sorting instead of reusing a partially consumed one
  3. Collect into a Vec and sort that if iteration already began
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at crates/bevy_ecs/src/query/iter.rs:1011 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20). Data as JSON: /api/errors/3c737dd6cb28f937. Report an issue: GitHub.