bevyengine/bevy · error · syn::Error

`type_path` already set to {}

Error message

`type_path` already set to {}

What it means

`#[reflect(type_path = <bool>)]` toggles automatic `TypePath` generation by the Reflect derive. Like `from_reflect`, it can only be set once: `parse_type_path` (crates/bevy_reflect/derive/src/container_attributes.rs:462) errors with "`type_path` already set to {previous}" on a second, conflicting value. The `TypePath` derive/`#[reflect(TypePath)]` provenance forces `true` via the mapper override, so mixing it with `type_path = false` triggers the error.

Source

Thrown at crates/bevy_reflect/derive/src/container_attributes.rs:481

        &mut self,
        input: ParseStream,
        trait_: ReflectTraitToImpl,
    ) -> syn::Result<()> {
        let pair = input.parse::<MetaNameValue>()?;
        let extracted_bool = extract_bool(&pair.value, |lit| {
            // Override `lit` if this is a `FromReflect` derive.
            // This typically means a user is opting out of the default implementation
            // from the `Reflect` derive and using the `FromReflect` derive directly instead.
            if trait_ == ReflectTraitToImpl::TypePath {
                LitBool::new(true, Span::call_site())
            } else {
                lit.clone()
            }
        })?;

        if let Some(existing) = &self.type_path_attrs.auto_derive {
            if existing.value() != extracted_bool.value() {
                return Err(syn::Error::new(
                    extracted_bool.span(),
                    format!("`{TYPE_PATH_ATTR}` already set to {}", existing.value()),
                ));
            }
        } else {
            self.type_path_attrs.auto_derive = Some(extracted_bool);
        }

        Ok(())
    }

    /// Returns true if the given reflected trait name (i.e. `ReflectDefault` for `Default`)
    /// is registered for this type.
    pub fn contains(&self, name: &str) -> bool {
        self.type_data
            .iter()
            .any(|data| data.reflect_path().is_ident(name))
    }

View on GitHub (pinned to 396ca72708)

Solutions

  1. Choose one source of truth: the `TypePath` derive (true) or `#[reflect(type_path = false)]`, never both
  2. If you disabled it to supply a custom path, make sure no `TypePath` derive remains on the type
  3. Consolidate reflect attributes into a single list

Example fix

// before: "`type_path` already set to false"
#[derive(Reflect, TypePath)]
#[reflect(type_path = false)]
struct Foo;

// after: keep the explicit setting, drop the conflicting derive
#[derive(Reflect)]
#[reflect(type_path = false)]
impl std::fmt::Debug for Foo { /* ... */ }
Defensive patterns

Strategy: validation

Validate before calling

null

Prevention

When it happens

Trigger: `#[derive(Reflect, TypePath)]` plus `#[reflect(type_path = false)]`, or two `#[reflect(...)]` lists giving different bools for `type_path`. Same-value repetition is allowed.

Common situations: Disabling generated TypePath (e.g. for a custom `#[type_path = "..."]` setup or generic workaround) while another derive or attribute still enables it; attribute lists duplicated during refactors.

Related errors


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