bevyengine/bevy · error · syn::Error
conflicting type data registration
Error message
conflicting type data registration
What it means
The bevy_reflect derive stores each special registration (Clone, Debug, PartialEq, PartialOrd, Hash) as a single optional impl. While parsing `#[reflect(...)]`, the plain form (`#[reflect(Hash)]`, sets `Implemented`) and the custom-function form (`#[reflect(Hash(my_fn))]`, merges `Custom`) share that one slot; `TraitImpl::merge` (crates/bevy_reflect/derive/src/container_attributes.rs:67) returns the compile error "conflicting type data registration" when both sides already carry an implementation.
Source
Thrown at crates/bevy_reflect/derive/src/container_attributes.rs:75
/// The trait is registered with a custom function rather than an actual implementation.
Custom(Path, Span),
}
impl TraitImpl {
/// Merges this [`TraitImpl`] with another.
///
/// Update `self` with whichever value is not [`TraitImpl::NotImplemented`].
/// If `other` is [`TraitImpl::NotImplemented`], then `self` is not modified.
/// An error is returned if neither value is [`TraitImpl::NotImplemented`].
pub fn merge(&mut self, other: TraitImpl) -> Result<(), syn::Error> {
match (&self, other) {
(TraitImpl::NotImplemented, value) => {
*self = value;
Ok(())
}
(_, TraitImpl::NotImplemented) => Ok(()),
(_, TraitImpl::Implemented(span) | TraitImpl::Custom(_, span)) => {
Err(syn::Error::new(span, CONFLICTING_TYPE_DATA_MESSAGE))
}
}
}
}
/// A collection of attributes used for deriving `FromReflect`.
#[derive(Clone, Default)]
pub(crate) struct FromReflectAttrs {
auto_derive: Option<LitBool>,
}
impl FromReflectAttrs {
/// Returns true if `FromReflect` should be automatically derived as part of the `Reflect` derive.
pub fn should_auto_derive(&self) -> bool {
self.auto_derive.as_ref().is_none_or(LitBool::value)
}
}
View on GitHub (pinned to 396ca72708)
Solutions
- Register each trait exactly once per type
- If you need a custom function, use only the custom form: replace `#[reflect(Hash)]` with `#[reflect(my_hash_fn)]`-style `#[reflect(Hash(my_hash_fn))]`, not both
- Consolidate everything into a single `#[reflect(...)]` list so duplicates are visually obvious
Example fix
// before: Hash registered twice -> conflicting type data registration
#[derive(Reflect)]
#[reflect(Hash, Hash(custom_hash_fn))]
struct Foo { ... }
// after: single custom registration
#[derive(Reflect)]
#[reflect(Hash(custom_hash_fn))]
struct Foo { ... } Defensive patterns
Strategy: validation
Validate before calling
null
Prevention
- One `#[reflect(...)]` list per type; review it as a whole after refactors
- Each of Clone/Debug/PartialEq/PartialOrd/Hash appears at most once, in either the plain or the custom-function form
- When adding a custom fn registration, delete the plain `#[reflect(Hash)]` entry it replaces
When it happens
Trigger: Listing one of the specially-handled traits twice on the same type with implementations on both sides: `#[reflect(Hash, Hash(my_hash_fn))]`, `#[reflect(Debug(custom), Debug)]`, or two custom functions `#[reflect(Debug(a), Debug(b))]` — including across multiple `#[reflect(...)]` attribute lists.
Common situations: Copy-pasting reflect attributes and merging the lists by hand; upgrading old code that had `#[reflect(Hash)]` plus a newer custom-function registration added next to it instead of replacing it.
Related errors
- `from_reflect` already set to {}
- `type_path` already set to {}
- Expected a boolean value
- `#[reflect("...")]` must use parentheses `(` and `)`
- `#[type_path = "..."]` must be a string literal
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/0d5e4dc144d10f3a.
Report an issue: GitHub.