{"record":{"id":"350bfebf59281b91","repo":"linebender/druid","slug":"expected-selector-but-the-command-was","errorCode":null,"errorMessage":"Expected selector \"{}\" but the command was \"{}\".","messagePattern":"Expected selector \"(.+?)\" but the command was \"(.+?)\"\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"druid/src/command.rs","lineNumber":503,"sourceCode":"    }\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    ///\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`]: #method.get\n    pub fn get_unchecked<T: Any>(&self, selector: Selector<T>) -> &T {\n        self.get(selector).unwrap_or_else(|| {\n            panic!(\n                \"Expected selector \\\"{}\\\" but the command was \\\"{}\\\".\",\n                selector.symbol(),\n                self.symbol\n            )\n        })\n    }\n}\n\nimpl Notification {\n    /// Returns `true` if `self` matches this [`Selector`].\n    pub fn is<T>(&self, selector: Selector<T>) -> bool {\n        self.symbol == selector.symbol()\n    }\n\n    /// Returns the payload for this [`Selector`], if the selector matches.\n    ///\n    /// # Panics\n    ///","sourceCodeStart":485,"sourceCodeEnd":521,"githubUrl":"https://github.com/linebender/druid/blob/0f8b1195e4e073f9597f2865299c3d18f8e4005f/druid/src/command.rs#L485-L521","documentation":"Druid's Command::get_unchecked<T> panics when the command being handled does not carry the requested Selector<T> — the command's symbol differs from the selector's symbol, so get(selector) returned None. Because get_unchecked skips the Option check, the library cannot recover and aborts. This typically means the widget thought it was receiving one command but got another, or two Selector keys with the same string but different types collide.","triggerScenarios":"Calling command.get_unchecked(MY_SELECTOR) inside a widget's command() handler when the notification order delivers a different command (e.g. another widget's command with a colliding or forwarded selector). Defining two Selector::new(\"save\") constants with different type parameters, so the wrong one matches at runtime. Handling a command in the wrong scope: a sub-window (via new_sub_window) or an edited target returns a command whose selector the parent widget then unwraps unchecked. A typo or copy-pasted Selector key string reused across unrelated features.","commonSituations":"Copy-pasting a Selector declaration and forgetting to change the key string, so two features share one key with different payloads. A widget that registers for multiple commands but uses get_unchecked for all of them instead of is() guards. Window/controller code (new_window, show_open_panel, show_save_panel, invalidate_ime) assuming the returned command is always the one they just sent when another handler intercepted it.","solutions":["Guard with command.is(selector) before calling get_unchecked, and handle or ignore non-matching commands instead of unwrapping.","Use the safe Command::get(selector) which returns Option<&T>, and match on None gracefully.","Audit all Selector::new key strings for duplicates; give every selector a unique key (conventionally prefixed with the module/feature name).","Ensure the command's Target matches: commands sent to a sub-window or specific widget id may be consumed elsewhere; verify the widget actually is the intended recipient.","If you own both sides, change get_unchecked to get and log the unexpected selector rather than panicking in release builds."],"exampleFix":"// before\nselector!(OPEN_FILE: Arc<PathBuf>);\nfn command(&mut self, ctx, cmd) {\n    let path = cmd.get_unchecked(OPEN_FILE);\n    ...\n}\n// after\nfn command(&mut self, ctx, cmd) {\n    if let Some(path) = cmd.get(OPEN_FILE) {\n        ...\n    }\n}","handlingStrategy":"type-guard","validationCode":"// before unwrapping in a widget handler:\nif !cmd.is(MY_SELECTOR) {\n    return; // not our command; let others handle it\n}","typeGuard":"fn is_my_selector<T>(cmd: &Command, sel: Selector<T>) -> bool {\n    cmd.is(sel)\n}","tryCatchPattern":null,"preventionTips":["Never call get_unchecked in a command handler that processes more than one possible command.","Prefer cmd.get(sel) returning Option over get_unchecked everywhere.","Give every Selector a globally unique key string, prefixed by module name.","Verify the command's target scope (WindowId/WidgetId) matches the widget doing the get."],"tags":["rust","druid","panic","selector","command"],"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"}