bevyengine/bevy · error

Cannot call `ReflectComponent::reflect_unchecked_mut` on com

Error message

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

What it means

`reflect_unchecked_mut` is the unsafe variant of `ReflectComponent`'s mutable access: it skips aliasing checks and directly returns a `&mut dyn Reflect` for the component. Like `reflect_mut`, it is guarded by the component's declared mutability — for a component with `type Mutability = Immutable`, the guard panics rather than let reflection break the immutability contract, even though the caller already opted into `unsafe`.

Source

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

            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`
                // guard ensures `C` is a mutable component
                let c = unsafe { entity.get_mut_assume_mutable::<C>() };
                c.map(|c| c.map_unchanged(|value| value as &mut dyn Reflect))
            },
            register_component: |world: &mut World| -> ComponentId {
                world.register_component::<C>()
            },
            map_entities: |reflect: &mut dyn Reflect, mut mapper: &mut dyn EntityMapper| {
                let component = reflect.downcast_mut::<C>().unwrap();
                Component::map_entities(component, &mut mapper);
            },
        })
    }
}

View on GitHub (pinned to 396ca72708)

Solutions

  1. Switch to the immutable workflow: `reflect()` to read, construct the replacement value, `insert()` to write
  2. If the component genuinely needs reflective mutation, declare `type Mutability = Mutable` in its `Component` impl
  3. Guard tooling loops so immutable components are filtered out before the unsafe call

Example fix

// before
let c = unsafe { reflect_component.reflect_unchecked_mut(entity_cell) }; // panics for Immutable

// after — make the component mutable, or replace instead of mutating
impl Component for Marker { type Mutability = Mutable; }
Defensive patterns

Strategy: validation

Validate before calling

// Before the unchecked path, verify the component's mutability
if <C as Component>::Mutability::MUTABLE {
    let c = unsafe { reflect_component.reflect_unchecked_mut(entity_cell) };
} else {
    // read-only path: reflect() then insert() a replacement
}

Type guard

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

Prevention

When it happens

Trigger: Calling `ReflectComponent::reflect_unchecked_mut` (or an `UnsafeEntityCell`-based reflective mutation path) on a component whose `Component::Mutability` is `Immutable` — typically deep editor, scene-spawn, or framework code that uses the unchecked API for performance on all components.

Common situations: Porting internal tooling from Bevy versions before mutable/immutable components existed (all components were mutable); inspector or replay tools that iterate every registered `ReflectComponent` and call the unchecked mutator; user hierarchies built on `ChildOf` (immutable) being edited reflectively.

Related errors


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