{"record":{"id":"13fccfa63f240ccf","repo":"linebender/druid","slug":"release-input-lock-was-called-on-a-winhandler-that","errorCode":null,"errorMessage":"release_input_lock was called on a WinHandler that did not expect text input.","messagePattern":"release_input_lock was called on a WinHandler that did not expect text input\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"druid-shell/src/window.rs","lineNumber":670,"sourceCode":"    ///\n    /// For more information, see [the text input documentation](crate::text).\n    ///\n    /// [`release_input_lock`]: WinHandler::release_input_lock\n    #[allow(unused_variables)]\n    fn acquire_input_lock(\n        &mut self,\n        token: TextFieldToken,\n        mutable: bool,\n    ) -> Box<dyn InputHandler> {\n        panic!(\"acquire_input_lock was called on a WinHandler that did not expect text input.\")\n    }\n\n    /// Release a lock previously acquired by [`acquire_input_lock`].\n    ///\n    /// [`acquire_input_lock`]: WinHandler::acquire_input_lock\n    #[allow(unused_variables)]\n    fn release_input_lock(&mut self, token: TextFieldToken) {\n        panic!(\"release_input_lock was called on a WinHandler that did not expect text input.\")\n    }\n\n    /// Called on a mouse wheel event.\n    ///\n    /// The polarity is the amount to be added to the scroll position,\n    /// in other words the opposite of the direction the content should\n    /// move on scrolling. This polarity is consistent with the\n    /// deltaX and deltaY values in a web [WheelEvent].\n    ///\n    /// [WheelEvent]: https://w3c.github.io/uievents/#event-type-wheel\n    #[allow(unused_variables)]\n    fn wheel(&mut self, event: &MouseEvent) {}\n\n    /// Called when a platform-defined zoom gesture occurs (such as pinching\n    /// on the trackpad).\n    #[allow(unused_variables)]\n    fn zoom(&mut self, delta: f64) {}\n","sourceCodeStart":652,"sourceCodeEnd":688,"githubUrl":"https://github.com/linebender/druid/blob/0f8b1195e4e073f9597f2865299c3d18f8e4005f/druid-shell/src/window.rs#L652-L688","documentation":"This panic is the default (no-op) implementation of `WinHandler::release_input_lock` in druid-shell's window.rs. The shell calls it when a platform text-input path finishes editing and tries to release the lock acquired via `acquire_input_lock`, but the handler's default implementation did not expect any text input. It mirrors the acquire-side panic and signals the same contract violation on the release path.","triggerScenarios":"The backend completes a text-editing session and calls `release_input_lock(token)` on a WinHandler using the default trait implementation that never registered text fields or overrode the lock methods.","commonSituations":"Custom WinHandlers with default trait impls receiving IME events; a text field whose acquire was handled elsewhere but release lands on the default; version skew where druid-shell added the lock API after the handler was written.","solutions":["Override `release_input_lock` in your WinHandler to unlock the state corresponding to the given TextFieldToken","Also override `acquire_input_lock` — if release fired, acquire likely did too; implement both symmetrically","Track which tokens were acquired so release can be matched correctly (map from token to handler state)"],"exampleFix":"// before\nimpl WinHandler for MyAppHandler {} // panicking defaults\n// after\nimpl WinHandler for MyAppHandler {\n    fn release_input_lock(&mut self, token: TextFieldToken) {\n        if let Some(field) = self.text_field_for(token) {\n            field.unlock_input();\n        }\n    }\n}","handlingStrategy":"type-guard","validationCode":"// Only release locks for tokens the handler actually acquired:\nfn has_acquired(handler: &MyHandler, token: TextFieldToken) -> bool {\n    handler.acquired_tokens.contains(&token)\n}\n","typeGuard":"fn handles_text_input(handler: &dyn WinHandler) -> bool {\n    !handler.text_widgets().is_empty()\n}\n","tryCatchPattern":"// Avoid relying on panic recovery; guard instead:\nif handler.handles_text_input() {\n    handler.release_input_lock(token);\n} else {\n    tracing::warn!(\"release_input_lock on non-text handler ignored\");\n}\n","preventionTips":["Always override release_input_lock together with acquire_input_lock","Track acquired tokens in a set and only release known tokens","Audit WinHandler impls after upgrading druid-shell for new text-input trait methods","Exercise IME/candidate-window paths in tests so release is covered"],"tags":["rust","druid-shell","text-input","winhandler"],"backgroundTag":"method-not-implemented","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"}