{"record":{"id":"9470797a7fd44843","repo":"linebender/druid","slug":"the-selector-exists-twice-with-different-type","errorCode":null,"errorMessage":"The selector \"{}\" exists twice with different types. See druid::Command::get for more information","messagePattern":"The selector \"(.+?)\" exists twice with different types\\. See druid::Command::get for more information","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"druid/src/command.rs","lineNumber":477,"sourceCode":"    }\n\n    /// Returns `Some(&T)` (this `Command`'s payload) if the selector matches.\n    ///\n    /// Returns `None` when `self.is(selector) == false`.\n    ///\n    /// Alternatively you can check the selector with [`is`] and then use [`get_unchecked`].\n    ///\n    /// # Panics\n    ///\n    /// Panics when the payload has a different type, than what the selector is supposed to carry.\n    /// This can happen when two selectors with different types but the same key are used.\n    ///\n    /// [`is`]: #method.is\n    /// [`get_unchecked`]: #method.get_unchecked\n    pub fn get<T: Any>(&self, selector: Selector<T>) -> Option<&T> {\n        if self.symbol == selector.symbol() {\n            Some(self.payload.downcast_ref().unwrap_or_else(|| {\n                panic!(\n                    \"The selector \\\"{}\\\" exists twice with different types. See druid::Command::get for more information\",\n                    selector.symbol()\n                );\n            }))\n        } else {\n            None\n        }\n    }\n\n    /// Returns a reference to this `Command`'s payload.\n    ///\n    /// If the selector has already been checked with [`is`], then `get_unchecked` can be used safely.\n    /// Otherwise you should use [`get`] instead.\n    ///\n    /// # Panics\n    ///\n    /// Panics when `self.is(selector) == false`.\n    ///","sourceCodeStart":459,"sourceCodeEnd":495,"githubUrl":"https://github.com/linebender/druid/blob/0f8b1195e4e073f9597f2865299c3d18f8e4005f/druid/src/command.rs#L459-L495","documentation":"This panic comes from `Command::get<T>` in druid's command.rs. Selectors are interned once (a `Selector<T>` with a unique symbol), but a selector string can be recreated with a different type parameter, producing two `Selector` values sharing the same symbol with different payload types. When `get` matches on the symbol but the stored payload cannot downcast to `T`, the library panics because it cannot satisfy the type contract.","triggerScenarios":"Two modules each declare `Selector::new(\"my.command\")` with different payload types (e.g. one `Selector<u32>`, one `Selector<String>`), then a command posted with one type is read with `get` using the other; re-declaring the same selector string in a refactor that changed its payload type.","commonSituations":"Copy-pasting a selector name across crates/modules with different payload generics; renaming/refactoring payload types without changing the selector string; hot-reload or dynamic loading creating two interned symbols; reading a command with the wrong generic in a `Widget::event` handler.","solutions":["Ensure each selector string is declared exactly once with one type — share it via a public constant instead of re-declaring it","Use `Command::get_unchecked` only if you are certain of the payload type; prefer fixing the type mismatch","Rename the selector string if its payload type genuinely changed so old and new do not collide","Search the codebase for duplicate `Selector::new(\"...\")` calls with the reported symbol name"],"exampleFix":"// before\n// module_a.rs\npub const SET_SIZE: Selector<u32> = Selector::new(\"app.set-size\");\n// module_b.rs\npub const SET_SIZE: Selector<String> = Selector::new(\"app.set-size\"); // duplicate symbol, different type\n// after\n// shared.rs\npub const SET_SIZE: Selector<u32> = Selector::new(\"app.set-size\");\n// both modules use shared::SET_SIZE","handlingStrategy":"validation","validationCode":"// Ensure each selector string is declared exactly once; check with a test:\n#[test]\nfn selectors_are_unique() {\n    let a = Selector::new(\"app.set-size\") as Selector<u32>;\n    let b = module_b::SET_SIZE;\n    assert!(a.symbol() != b.symbol() || std::any::TypeId::of::<u32>() == std::any::TypeId::of::<String>(), \"duplicate selector with different type\");\n}\n","typeGuard":"// Narrow safely instead of panicking get:\nfn get_checked<T: Any>(cmd: &Command, selector: Selector<T>) -> Option<&T> {\n    cmd.get(selector) // wraps downcast; ensure only ONE Selector::new per string exists\n}\n// Prefer checking payload type first:\ncmd.payload.is::<T>()\n","tryCatchPattern":"// Rust panics are not catchable in normal code; only if unavoidable:\nlet result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    command.get(MY_SELECTOR).cloned()\n}));\nmatch result {\n    Ok(v) => { /* payload matched */ }\n    Err(_) => eprintln!(\"selector declared twice with different types\"),\n}\n","preventionTips":["Declare every selector once in a shared module and import it everywhere","Never re-create a selector string with a different payload type","grep for duplicate Selector::new calls with the same string when panics mention a symbol","When changing a payload type, also change the selector string to invalidate stale postings","Add a unit test asserting selector symbol uniqueness across the crate"],"tags":["rust","druid","selectors","type-safety"],"backgroundTag":"type-mismatch","analyzedSha":"0f8b1195e4e073f9597f2865299c3d18f8e4005f","analyzedAt":"2026-09-10T14:27:34.582Z","contentChangedAt":"2026-09-10T14:27:34.582Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}