linebender/druid · error
acquire_input_lock was called on a WinHandler that did not…
Error message
acquire_input_lock was called on a WinHandler that did not expect text input.
What it means
This panic is the default (no-op) implementation of `WinHandler::acquire_input_lock` in druid-shell's window.rs. The shell calls it when a platform IME/text-input path tries to lock a text field, but the application's WinHandler never registered text fields, so it has no InputHandler to return. It is a contract violation: the handler received a text-input request it did not opt into.
Solutions
- Override `acquire_input_lock` in your WinHandler to return the InputHandler for the given TextFieldToken
- Ensure the token passed corresponds to a text field your handler actually registered; verify what token the platform is asking for
- If your app has no text input at all, check why the backend is requesting a lock (stray focus/IME event) and guard the widget registration
Example fix
// before
impl WinHandler for MyAppHandler {} // uses panicking default
// after
impl WinHandler for MyAppHandler {
fn acquire_input_lock(
&mut self,
token: TextFieldToken,
mutable: bool,
) -> Box<dyn InputHandler> {
match self.text_field_for(token) {
Some(field) => Box::new(field.lock_input(mutable)),
None => Box::new(NullInputHandler),
}
}
} Defensive patterns
Strategy: type-guard
Validate before calling
// Before enabling text input, verify the handler implements the input-lock API:
fn supports_text_input(handler: &dyn WinHandler, token: TextFieldToken) -> bool {
handler.text_widgets().contains(&token)
}
Type guard
fn handler_overrides_input_lock(handler: &dyn WinHandler) -> bool {
// default impl panics; only route text events to handlers that registered fields
!handler.text_widgets().is_empty()
}
Try / catch
// Rust panics are not catchable in normal code; if you must:
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
handler.acquire_input_lock(token, true)
}));
if result.is_err() { tracing::error!("handler does not support text input"); }
Prevention
- Override acquire_input_lock/release_input_lock whenever your WinHandler registers text fields
- Keep text field registration and lock overrides in the same impl block
- Test with IME input enabled to exercise the lock path
- After druid-shell upgrades, audit WinHandler impls against the trait's new methods
When it happens
Trigger: The platform backend (e.g. IME focus handling) calls `acquire_input_lock(token, mutable)` on a WinHandler whose default trait method was not overridden and which never returned a matching TextFieldToken from `text_widgets`/focus tracking.
Common situations: Custom WinHandler implementations that use the default trait impls; IME or accessibility events arriving for a text field that was removed or never registered; upgrading druid-shell where the backend now routes input through the lock API for handlers written against older versions.
Related errors
- release_input_lock was called on a WinHandler that did not…
- The main thread status has already been claimed by thread
- No path received for filename
- More than one path received for single selection
- There is no globally active Application
AI-assisted analysis of linebender/druid@0f8b1195e4 (2026-09-10).
Data as JSON: /api/errors/6e9437f6ddd14c51.
Report an issue: GitHub.
Appendix: source
Thrown at druid-shell/src/window.rs:662
/// Take a lock for the text document specified by `token`.
///
/// All calls to this method must be balanced with a call to
/// [`release_input_lock`].
///
/// If `mutable` is true, the lock should be a write lock, and allow calling
/// mutating methods on InputHandler. This method is called from the top
/// level of the event loop and expects to acquire a lock successfully.
///
/// For more information, see [the text input documentation](crate::text).
///
/// [`release_input_lock`]: WinHandler::release_input_lock
#[allow(unused_variables)]
fn acquire_input_lock(
&mut self,
token: TextFieldToken,
mutable: bool,
) -> Box<dyn InputHandler> {
panic!("acquire_input_lock was called on a WinHandler that did not expect text input.")
}
/// Release a lock previously acquired by [`acquire_input_lock`].
///
/// [`acquire_input_lock`]: WinHandler::acquire_input_lock
#[allow(unused_variables)]
fn release_input_lock(&mut self, token: TextFieldToken) {
panic!("release_input_lock was called on a WinHandler that did not expect text input.")
}
/// Called on a mouse wheel event.
///
/// The polarity is the amount to be added to the scroll position,
/// in other words the opposite of the direction the content should
/// move on scrolling. This polarity is consistent with the
/// deltaX and deltaY values in a web [WheelEvent].
///
/// [WheelEvent]: https://w3c.github.io/uievents/#event-type-wheelView on GitHub (pinned to 0f8b1195e4)