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

  1. Override `acquire_input_lock` in your WinHandler to return the InputHandler for the given TextFieldToken
  2. Ensure the token passed corresponds to a text field your handler actually registered; verify what token the platform is asking for
  3. 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

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


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-wheel

View on GitHub (pinned to 0f8b1195e4)