bevyengine/bevy · error

Cannot call `ReflectComponent::reflect_mut` on component {na

Error message

Cannot call `ReflectComponent::reflect_mut` on component {name}. It is immutable, and cannot modified through reflection

What it means

Bevy's `ReflectComponent` exposes a component on an entity for reflective access. `reflect_mut` is the path that hands out a `&mut dyn Reflect` for in-place editing, but components can declare `type Mutability = Immutable` in their `Component` impl to opt out. When the registered component's `C::Mutability::MUTABLE` is false, this closure panics instead of returning a mutable reference, because handing one out would bypass the immutability guarantee the type declared.

Source

Thrown at crates/bevy_ecs/src/reflect/component.rs:379

                entity
                    .take::<C>()
                    .map(|component| Box::new(component).into_reflect())
            },
            contains: |entity| entity.contains::<C>(),
            copy: |source_world, destination_world, source_entity, destination_entity, registry| {
                let source_component = source_world.get::<C>(source_entity).unwrap();
                let destination_component =
                    from_reflect_with_fallback::<C>(source_component, destination_world, registry);
                destination_world
                    .entity_mut(destination_entity)
                    .insert(destination_component);
            },
            reflect: |entity| entity.get::<C>().map(|c| c as &dyn Reflect),
            reflect_mut: |entity| {
                if !C::Mutability::MUTABLE {
                    let name = DebugName::type_name::<C>();
                    let name = name.shortname();
                    panic!("Cannot call `ReflectComponent::reflect_mut` on component {name}. It is immutable, and cannot modified through reflection");
                }

                // SAFETY: guard ensures `C` is a mutable component
                unsafe {
                    entity
                        .into_mut_assume_mutable::<C>()
                        .map(|c| c.map_unchanged(|value| value as &mut dyn Reflect))
                }
            },
            reflect_unchecked_mut: |entity| {
                if !C::Mutability::MUTABLE {
                    let name = DebugName::type_name::<C>();
                    let name = name.shortname();
                    panic!("Cannot call `ReflectComponent::reflect_unchecked_mut` on component {name}. It is immutable, and cannot modified through reflection");
                }

                // SAFETY: reflect_unchecked_mut is an unsafe function pointer used by
                // `reflect_unchecked_mut` which must be called with an UnsafeEntityCell with access to the component `C` on the `entity`

View on GitHub (pinned to 396ca72708)

Solutions

  1. Use the immutable path: read via `ReflectComponent::reflect`, build the new value, then replace it with `ReflectComponent::insert` (remove + insert, never in-place mutation)
  2. If in-place reflective mutation is a real requirement, change the component's definition to `type Mutability = Mutable`
  3. In editor/tooling code, check `C::Mutability::MUTABLE` (statically) or maintain a skip-list of immutable components and present them as read-only

Example fix

// before
#[derive(Component, Reflect)]
#[reflect(Component)]
struct Health(f32);
impl Component for Health { type Mutability = Immutable; }
let reflected = reflect_component.reflect_mut(&mut entity); // panics

// after — allow reflective mutation
impl Component for Health { type Mutability = Mutable; }
Defensive patterns

Strategy: validation

Validate before calling

// Statically-known component: check mutability before the mutable path
fn can_reflect_mut<C: Component>() -> bool {
    <C as Component>::Mutability::MUTABLE
}

if can_reflect_mut::<MyComponent>() {
    let r = reflect_component.reflect_mut(&mut entity_mut);
} else {
    let r = reflect_component.reflect(&entity);
    // build replacement and reflect_component.insert(...) instead
}

Type guard

fn is_reflect_mutable<C: Component>() -> bool { C::Mutability::MUTABLE }

Prevention

When it happens

Trigger: Calling `ReflectComponent::reflect_mut` (or any `ReflectMut`-based editing path) on a component declared `Immutable` — e.g. an editor/inspector crate mutating every component on an entity via reflection, hitting a component like `ChildOf` that Bevy defines as immutable, or user code doing `registry`-driven component patching that assumes all components are mutable.

Common situations: Using bevy_editor_pls / bevy_inspector_egui or custom scene tooling on a codebase that adopted immutable components (Bevy 0.15+); upgrading a project where a component was changed to Immutable while generic reflection code still calls reflect_mut on it; serializers that apply patches to all registered components indiscriminately.

Related errors


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