zed-industries/zed · error

Type mismatch in reflection wrapper

Error message

Type mismatch in reflection wrapper

What it means

gpui's inspector-reflection derive generates __wrapper_<method> functions that receive a Box<dyn Any>, downcast it to the concrete type T implementing the trait, and call the method. If the runtime value is not exactly that T, the downcast fails and the wrapper panics with 'Type mismatch in reflection wrapper'. This is an internal invariant of gpui's dev-tools inspector: a wrapper generated for one concrete type must only be invoked on values of that type.

Source

Thrown at crates/gpui_macros/src/derive_inspector_reflection.rs:107

    let reflection_mod_name = Ident::new(
        &format!("{}_reflection", trait_name.to_string().to_snake_case()),
        trait_name.span(),
    );

    // Generate wrapper functions for each method
    // These wrappers use type erasure to allow runtime invocation
    let wrapper_functions = method_infos.iter().map(|(method_name, _doc, cfg_attrs)| {
        let wrapper_name = Ident::new(
            &format!("__wrapper_{}", method_name),
            method_name.span(),
        );
        quote! {
            #(#cfg_attrs)*
            fn #wrapper_name<T: #trait_name + 'static>(value: Box<dyn std::any::Any>) -> Box<dyn std::any::Any> {
                if let Ok(concrete) = value.downcast::<T>() {
                    Box::new(concrete.#method_name())
                } else {
                    panic!("Type mismatch in reflection wrapper");
                }
            }
        }
    });

    // Generate method info entries
    let method_info_entries = method_infos.iter().map(|(method_name, doc, cfg_attrs)| {
        let method_name_str = method_name.to_string();
        let wrapper_name = Ident::new(&format!("__wrapper_{}", method_name), method_name.span());
        let doc_expr = match doc {
            Some(doc_str) => quote! { Some(#doc_str) },
            None => quote! { None },
        };
        quote! {
            #(#cfg_attrs)*
            #inspector_reflection_path::FunctionReflection {
                name: #method_name_str,
                function: #wrapper_name::<T>,

View on GitHub (pinned to f4178619ac)

Solutions

  1. Verify the value handed to the reflection wrapper was created from the exact concrete type the wrapper was generated for
  2. Key the reflection registry by (TypeId, method_name) instead of method_name alone so a wrong pairing cannot be invoked
  3. If you control gpui, change the wrapper to downcast_ref and return an error/skip instead of panicking
  4. Do a clean rebuild (cargo clean) so stale monomorphized wrappers are not reused after type refactors

Example fix

// before: wrapper panics on any mismatch
fn __wrapper_label<T: Labeled + 'static>(value: Box<dyn Any>) -> Box<dyn Any> {
    if let Ok(concrete) = value.downcast::<T>() {
        Box::new(concrete.label())
    } else {
        panic!("Type mismatch in reflection wrapper");
    }
}

// after: look up the wrapper by type id + method so the pairing is always correct
let wrapper = registry
    .get(&(value.type_id(), method_name))
    .ok_or_else(|| anyhow::anyhow!("no reflection wrapper for {method_name} on this type"))?;
wrapper(value)
Defensive patterns

Strategy: type-guard

Type guard

fn value_matches_wrapper_type<T: 'static>(value: &Box<dyn std::any::Any>) -> bool {
    value.is::<T>()
}

Prevention

When it happens

Trigger: Registering reflection for a type, then invoking the method wrapper with a value whose concrete type differs (e.g. the wrapper was instantiated for ViewA but receives a Box<ViewB> erased as Box<dyn Any>); generics/monomorphization mismatches where wrapper and value come from different instantiations.

Common situations: Building custom gpui dev-tools panels that reuse wrapper functions across different view types; refactoring types while stale reflection metadata stays registered; looking up wrappers by method name alone instead of by (type, method).

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/80d4fd209daa52c7. Report an issue: GitHub.