bevyengine/bevy · error

underlying type does not reflect `PartialEq` and hence doesn

Error message

underlying type does not reflect `PartialEq` and hence doesn't support equality checks

What it means

DynamicMap stores erased Box<dyn PartialReflect> keys in a hash table and looks them up by hashing and equality. internal_eq calls key.reflect_partial_eq(&**other) and expects the result: for types that do not reflect PartialEq, reflect_partial_eq returns None, and this expect panics with 'underlying type does not reflect `PartialEq`...'. Note DynamicMap::get/get_mut hash the key too, so key types also need reflected Hash.

Source

Thrown at crates/bevy_reflect/src/map.rs:263

        self.represented_type = represented_type;
    }

    /// Inserts a typed key-value pair into the map.
    pub fn insert<K: PartialReflect, V: PartialReflect>(&mut self, key: K, value: V) {
        self.insert_boxed(Box::new(key), Box::new(value));
    }

    fn internal_hash(value: &dyn PartialReflect) -> u64 {
        value.reflect_hash().expect(&hash_error!(value))
    }

    fn internal_eq(
        key: &dyn PartialReflect,
    ) -> impl FnMut(&(Box<dyn PartialReflect>, Box<dyn PartialReflect>)) -> bool + '_ {
        |(other, _)| {
            key
            .reflect_partial_eq(&**other)
            .expect("underlying type does not reflect `PartialEq` and hence doesn't support equality checks")
        }
    }
}

impl Map for DynamicMap {
    fn get(&self, key: &dyn PartialReflect) -> Option<&dyn PartialReflect> {
        self.hash_table
            .find(Self::internal_hash(key), Self::internal_eq(key))
            .map(|(_, value)| &**value)
    }

    fn get_mut(&mut self, key: &dyn PartialReflect) -> Option<&mut dyn PartialReflect> {
        self.hash_table
            .find_mut(Self::internal_hash(key), Self::internal_eq(key))
            .map(|(_, value)| &mut **value)
    }

    fn len(&self) -> usize {

View on GitHub (pinned to 396ca72708)

Solutions

  1. Add the missing reflect data to the key type: #[reflect(PartialEq, Hash)] (and derive/implement PartialEq + Hash) so reflect_partial_eq returns Some.
  2. Use simple key types that already reflect PartialEq/Hash (String, integers, Entity) for dynamic map keys.
  3. Check support before lookup: key.reflect_partial_eq(key.as_partial_reflect()).is_some() (and reflect_hash().is_some()) and fall back to iteration or rejection.
  4. If the key is dynamic, set represented type info via set_represented_type so it converts to a PartialEq-supporting type before use.

Example fix

// before
#[derive(Reflect, TypePath)]
#[reflect_value] // no PartialEq/Hash -> DynamicMap lookups panic
struct Key(u64);

// after
#[derive(Reflect, TypePath, PartialEq, Eq, Hash)]
#[reflect_value(PartialEq, Hash)]
struct Key(u64);
Defensive patterns

Strategy: validation

Validate before calling

fn key_supports_eq_and_hash(key: &dyn PartialReflect) -> bool {
    key.reflect_hash().is_some() && key.reflect_partial_eq(key.as_partial_reflect()).is_some()
}

if key_supports_eq_and_hash(probe.as_ref()) {
    let hit = dynamic_map.get(probe.as_ref());
} else {
    // iterate entries or reject the key type
}

Type guard

fn safe_dynamic_key<K: PartialReflect + ?Sized>(k: &K) -> Option<&K> {
    (k.reflect_partial_eq(k.as_partial_reflect()).is_some()).then_some(k)
}

Prevention

When it happens

Trigger: Calling DynamicMap::get/get_mut (or operations that look keys up) with a key whose type does not implement reflected PartialEq — e.g. a custom #[reflect_value] opaque type without #[reflect(PartialEq, Hash)], or a dynamic key that represents such a type.

Common situations: Custom opaque key types registered without PartialEq/Hash reflect data; building DynamicMap from user data with exotic keys; mirrors of typed maps where the key type changed into one lacking PartialEq.

Related errors


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