{"record":{"id":"80d4fd209daa52c7","repo":"zed-industries/zed","slug":"type-mismatch-in-reflection-wrapper","errorCode":null,"errorMessage":"Type mismatch in reflection wrapper","messagePattern":"Type mismatch in reflection wrapper","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gpui_macros/src/derive_inspector_reflection.rs","lineNumber":107,"sourceCode":"    let reflection_mod_name = Ident::new(\n        &format!(\"{}_reflection\", trait_name.to_string().to_snake_case()),\n        trait_name.span(),\n    );\n\n    // Generate wrapper functions for each method\n    // These wrappers use type erasure to allow runtime invocation\n    let wrapper_functions = method_infos.iter().map(|(method_name, _doc, cfg_attrs)| {\n        let wrapper_name = Ident::new(\n            &format!(\"__wrapper_{}\", method_name),\n            method_name.span(),\n        );\n        quote! {\n            #(#cfg_attrs)*\n            fn #wrapper_name<T: #trait_name + 'static>(value: Box<dyn std::any::Any>) -> Box<dyn std::any::Any> {\n                if let Ok(concrete) = value.downcast::<T>() {\n                    Box::new(concrete.#method_name())\n                } else {\n                    panic!(\"Type mismatch in reflection wrapper\");\n                }\n            }\n        }\n    });\n\n    // Generate method info entries\n    let method_info_entries = method_infos.iter().map(|(method_name, doc, cfg_attrs)| {\n        let method_name_str = method_name.to_string();\n        let wrapper_name = Ident::new(&format!(\"__wrapper_{}\", method_name), method_name.span());\n        let doc_expr = match doc {\n            Some(doc_str) => quote! { Some(#doc_str) },\n            None => quote! { None },\n        };\n        quote! {\n            #(#cfg_attrs)*\n            #inspector_reflection_path::FunctionReflection {\n                name: #method_name_str,\n                function: #wrapper_name::<T>,","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/zed-industries/zed/blob/f4178619acd0d47ea1f76a2025c42962c6d6638c/crates/gpui_macros/src/derive_inspector_reflection.rs#L89-L125","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Verify the value handed to the reflection wrapper was created from the exact concrete type the wrapper was generated for","Key the reflection registry by (TypeId, method_name) instead of method_name alone so a wrong pairing cannot be invoked","If you control gpui, change the wrapper to downcast_ref and return an error/skip instead of panicking","Do a clean rebuild (cargo clean) so stale monomorphized wrappers are not reused after type refactors"],"exampleFix":"// before: wrapper panics on any mismatch\nfn __wrapper_label<T: Labeled + 'static>(value: Box<dyn Any>) -> Box<dyn Any> {\n    if let Ok(concrete) = value.downcast::<T>() {\n        Box::new(concrete.label())\n    } else {\n        panic!(\"Type mismatch in reflection wrapper\");\n    }\n}\n\n// after: look up the wrapper by type id + method so the pairing is always correct\nlet wrapper = registry\n    .get(&(value.type_id(), method_name))\n    .ok_or_else(|| anyhow::anyhow!(\"no reflection wrapper for {method_name} on this type\"))?;\nwrapper(value)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn value_matches_wrapper_type<T: 'static>(value: &Box<dyn std::any::Any>) -> bool {\n    value.is::<T>()\n}","tryCatchPattern":null,"preventionTips":["Register and look up reflection wrappers keyed by std::any::TypeId plus method name, never by method name alone","Never share one wrapper function across different concrete types","Add a unit test per registered type asserting the wrapper round-trips without panicking"],"tags":["gpui","inspector","reflection","downcast","any"],"backgroundTag":"type-downcast-mismatch","analyzedSha":"f4178619acd0d47ea1f76a2025c42962c6d6638c","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}