Skip to main content

bevy_ecs/world/
error.rs

1//! Contains error types returned by bevy's schedule.
2
3use alloc::vec::Vec;
4use bevy_utils::prelude::DebugName;
5
6use crate::{
7    component::ComponentId,
8    entity::{Entity, EntityNotSpawnedError},
9    schedule::InternedScheduleLabel,
10};
11
12/// The error type returned by [`World::try_run_schedule`] if the provided schedule does not exist.
13///
14/// [`World::try_run_schedule`]: crate::world::World::try_run_schedule
15#[derive(#[allow(unused_qualifications)]
#[automatically_derived]
impl ::core::fmt::Display for TryRunScheduleError {
    #[allow(clippy :: used_underscore_binding)]
    fn fmt(&self, __formatter: &mut ::core::fmt::Formatter)
        -> ::core::fmt::Result {
        #[allow(unused_variables, deprecated)]
        let Self(_0) = self;
        match (_0,) {
            (__field0,) =>
                __formatter.write_fmt(format_args!("The schedule with the label {0:?} was not found.",
                        __field0)),
        }
    }
}thiserror::Error, #[automatically_derived]
impl ::core::fmt::Debug for TryRunScheduleError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "TryRunScheduleError", &&self.0)
    }
}Debug)]
16#[error("The schedule with the label {0:?} was not found.")]
17pub struct TryRunScheduleError(pub InternedScheduleLabel);
18
19/// The error type returned by [`World::try_insert_batch`] and [`World::try_insert_batch_if_new`]
20/// if any of the provided entities do not exist.
21///
22/// [`World::try_insert_batch`]: crate::world::World::try_insert_batch
23/// [`World::try_insert_batch_if_new`]: crate::world::World::try_insert_batch_if_new
24#[derive(#[allow(unused_qualifications)]
#[automatically_derived]
impl ::core::fmt::Display for TryInsertBatchError {
    #[allow(clippy :: used_underscore_binding)]
    fn fmt(&self, __formatter: &mut ::core::fmt::Formatter)
        -> ::core::fmt::Result {
        use ::thiserror::__private18::AsDisplay as _;
        #[allow(unused_variables, deprecated)]
        let Self { bundle_type, entities } = self;
        match (bundle_type.as_display(), entities) {
            (__display_bundle_type, __field_entities) =>
                __formatter.write_fmt(format_args!("Could not insert bundles of type {0} into the entities with the following IDs because they do not exist: {1:?}",
                        __display_bundle_type, __field_entities)),
        }
    }
}thiserror::Error, #[automatically_derived]
impl ::core::fmt::Debug for TryInsertBatchError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "TryInsertBatchError", "bundle_type", &self.bundle_type,
            "entities", &&self.entities)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for TryInsertBatchError {
    #[inline]
    fn clone(&self) -> TryInsertBatchError {
        TryInsertBatchError {
            bundle_type: ::core::clone::Clone::clone(&self.bundle_type),
            entities: ::core::clone::Clone::clone(&self.entities),
        }
    }
}Clone)]
25#[error("Could not insert bundles of type {bundle_type} into the entities with the following IDs because they do not exist: {entities:?}")]
26pub struct TryInsertBatchError {
27    /// The bundles' type name.
28    pub bundle_type: DebugName,
29    /// The IDs of the provided entities that do not exist.
30    pub entities: Vec<Entity>,
31}
32
33/// An error that occurs when a specified [`Entity`] could not be despawned.
34#[derive(fn from(source: EntityNotSpawnedError) -> Self {
    EntityDespawnError { 0: source }
}thiserror::Error, #[automatically_derived]
impl ::core::fmt::Debug for EntityDespawnError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "EntityDespawnError", &&self.0)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for EntityDespawnError {
    #[inline]
    fn clone(&self) -> EntityDespawnError {
        let _: ::core::clone::AssertParamIsClone<EntityNotSpawnedError>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for EntityDespawnError { }Copy)]
35#[error("Could not despawn entity: {0}")]
36pub struct EntityDespawnError(#[from] pub EntityNotSpawnedError);
37
38/// An error that occurs when dynamically retrieving components from an entity.
39#[derive(#[allow(unused_qualifications)]
#[automatically_derived]
impl ::core::fmt::Display for EntityComponentError {
    fn fmt(&self, __formatter: &mut ::core::fmt::Formatter)
        -> ::core::fmt::Result {

        #[allow(unused_variables, deprecated, clippy ::
        used_underscore_binding)]
        match self {
            EntityComponentError::MissingComponent(_0) =>
                match (_0,) {
                    (__field0,) =>
                        __formatter.write_fmt(format_args!("The component with ID {0:?} does not exist on the entity.",
                                __field0)),
                },
            EntityComponentError::AliasedMutability(_0) =>
                match (_0,) {
                    (__field0,) =>
                        __formatter.write_fmt(format_args!("The component with ID {0:?} was requested mutably more than once.",
                                __field0)),
                },
        }
    }
}thiserror::Error, #[automatically_derived]
impl ::core::fmt::Debug for EntityComponentError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            EntityComponentError::MissingComponent(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "MissingComponent", &__self_0),
            EntityComponentError::AliasedMutability(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "AliasedMutability", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for EntityComponentError {
    #[inline]
    fn clone(&self) -> EntityComponentError {
        let _: ::core::clone::AssertParamIsClone<ComponentId>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for EntityComponentError { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for EntityComponentError {
    #[inline]
    fn eq(&self, other: &EntityComponentError) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (EntityComponentError::MissingComponent(__self_0),
                    EntityComponentError::MissingComponent(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (EntityComponentError::AliasedMutability(__self_0),
                    EntityComponentError::AliasedMutability(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for EntityComponentError {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<ComponentId>;
    }
}Eq)]
40pub enum EntityComponentError {
41    /// The component with the given [`ComponentId`] does not exist on the entity.
42    #[error("The component with ID {0:?} does not exist on the entity.")]
43    MissingComponent(ComponentId),
44    /// The component with the given [`ComponentId`] was requested mutably more than once.
45    #[error("The component with ID {0:?} was requested mutably more than once.")]
46    AliasedMutability(ComponentId),
47}
48
49/// An error that occurs when fetching entities mutably from a world.
50#[derive(fn from(source: EntityNotSpawnedError) -> Self {
    EntityMutableFetchError::NotSpawned { 0: source }
}thiserror::Error, #[automatically_derived]
impl ::core::fmt::Debug for EntityMutableFetchError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            EntityMutableFetchError::NotSpawned(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "NotSpawned", &__self_0),
            EntityMutableFetchError::AliasedMutability(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "AliasedMutability", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for EntityMutableFetchError {
    #[inline]
    fn clone(&self) -> EntityMutableFetchError {
        let _: ::core::clone::AssertParamIsClone<EntityNotSpawnedError>;
        let _: ::core::clone::AssertParamIsClone<Entity>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for EntityMutableFetchError { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for EntityMutableFetchError {
    #[inline]
    fn eq(&self, other: &EntityMutableFetchError) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (EntityMutableFetchError::NotSpawned(__self_0),
                    EntityMutableFetchError::NotSpawned(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (EntityMutableFetchError::AliasedMutability(__self_0),
                    EntityMutableFetchError::AliasedMutability(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for EntityMutableFetchError {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<EntityNotSpawnedError>;
        let _: ::core::cmp::AssertParamIsEq<Entity>;
    }
}Eq)]
51pub enum EntityMutableFetchError {
52    /// The entity is not spawned.
53    #[error(
54        "{0}\n
55    If you were attempting to apply a command to this entity,
56    and want to handle this error gracefully, consider using `EntityCommands::queue_handled` or `queue_silenced`."
57    )]
58    NotSpawned(#[from] EntityNotSpawnedError),
59    /// The entity with the given ID was requested mutably more than once.
60    #[error("The entity with ID {0} was requested mutably more than once")]
61    AliasedMutability(Entity),
62}
63
64/// An error that occurs when getting a resource of a given type in a world.
65#[derive(#[allow(unused_qualifications)]
#[automatically_derived]
impl ::core::fmt::Display for ResourceFetchError {
    fn fmt(&self, __formatter: &mut ::core::fmt::Formatter)
        -> ::core::fmt::Result {

        #[allow(unused_variables, deprecated, clippy ::
        used_underscore_binding)]
        match self {
            ResourceFetchError::NotRegistered {} =>
                __formatter.write_str("The resource has never been initialized or registered with the world. Did you forget to add it using `app.insert_resource` / `app.init_resource`?"),
            ResourceFetchError::DoesNotExist(_0) =>
                match (_0,) {
                    (__field0,) =>
                        __formatter.write_fmt(format_args!("The resource with ID {0:?} does not currently exist in the world.",
                                __field0)),
                },
            ResourceFetchError::NoResourceAccess(_0) =>
                match (_0,) {
                    (__field0,) =>
                        __formatter.write_fmt(format_args!("Cannot get access to the resource with ID {0:?} in the world as it conflicts with an on going operation.",
                                __field0)),
                },
            ResourceFetchError::Immutable(_0) =>
                match (_0,) {
                    (__field0,) =>
                        __formatter.write_fmt(format_args!("Tried to mutably fetch resource with ID {0:?}, which is immutable",
                                __field0)),
                },
        }
    }
}thiserror::Error, #[automatically_derived]
impl ::core::fmt::Debug for ResourceFetchError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            ResourceFetchError::NotRegistered =>
                ::core::fmt::Formatter::write_str(f, "NotRegistered"),
            ResourceFetchError::DoesNotExist(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "DoesNotExist", &__self_0),
            ResourceFetchError::NoResourceAccess(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "NoResourceAccess", &__self_0),
            ResourceFetchError::Immutable(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Immutable", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for ResourceFetchError {
    #[inline]
    fn clone(&self) -> ResourceFetchError {
        let _: ::core::clone::AssertParamIsClone<ComponentId>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ResourceFetchError { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for ResourceFetchError {
    #[inline]
    fn eq(&self, other: &ResourceFetchError) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (ResourceFetchError::DoesNotExist(__self_0),
                    ResourceFetchError::DoesNotExist(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (ResourceFetchError::NoResourceAccess(__self_0),
                    ResourceFetchError::NoResourceAccess(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (ResourceFetchError::Immutable(__self_0),
                    ResourceFetchError::Immutable(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ResourceFetchError {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<ComponentId>;
    }
}Eq)]
66pub enum ResourceFetchError {
67    /// The resource has never been initialized or registered with the world.
68    #[error("The resource has never been initialized or registered with the world. Did you forget to add it using `app.insert_resource` / `app.init_resource`?")]
69    NotRegistered,
70    /// The resource with the given [`ComponentId`] does not currently exist in the world.
71    #[error("The resource with ID {0:?} does not currently exist in the world.")]
72    DoesNotExist(ComponentId),
73    /// Cannot get access to the resource with the given [`ComponentId`] in the world as it conflicts with an on going operation.
74    #[error("Cannot get access to the resource with ID {0:?} in the world as it conflicts with an on going operation.")]
75    NoResourceAccess(ComponentId),
76    /// Tried to mutably fetch an immutable resource.
77    #[error("Tried to mutably fetch resource with ID {0:?}, which is immutable")]
78    Immutable(ComponentId),
79}
80
81#[cfg(test)]
82mod tests {
83    use crate::{
84        prelude::*,
85        system::{command::trigger, RunSystemOnce},
86    };
87
88    // Inspired by https://github.com/bevyengine/bevy/issues/19623
89    #[test]
90    fn fixing_panicking_entity_commands() {
91        #[derive(EntityEvent)]
92        struct Kill(Entity);
93
94        #[derive(EntityEvent)]
95        struct FollowupEvent(Entity);
96
97        fn despawn(kill: On<Kill>, mut commands: Commands) {
98            commands.entity(kill.event_target()).despawn();
99        }
100
101        fn followup(kill: On<Kill>, mut commands: Commands) {
102            // When using a simple .trigger() here, this panics because the entity has already been despawned.
103            // Instead, we need to use `.queue_handled` or `.queue_silenced` to avoid the panic.
104            commands.queue_silenced(trigger(FollowupEvent(kill.event_target())));
105        }
106
107        let mut world = World::new();
108        // This test would pass if the order of these statements were swapped,
109        // even with panicking entity commands
110        world.add_observer(followup);
111        world.add_observer(despawn);
112
113        // Create an entity to test these observers with
114        world.spawn_empty();
115
116        // Trigger a kill event on the entity
117        fn kill_everything(mut commands: Commands, query: Query<Entity>) {
118            for id in query.iter() {
119                commands.trigger(Kill(id));
120            }
121        }
122        world.run_system_once(kill_everything).unwrap();
123    }
124}