Skip to content

Warp freezes (becomes unresponsive) when switching from English to Chinese IME (WeChat Input) while typing in WSL #9967

@RunMintOn

Description

@RunMintOn

Pre-submit Checks

  • I have searched Warp bugs and there are no duplicates
  • I have searched Warp known issues page and my issue is not there
  • I have an issue with AI and have included the debugging ID (Optional, but helps expedite the AI quality fix).
  • I have technical issue and have included the logs (optional, but helps expedite the bug fix).

Describe the bug

Warp becomes completely unresponsive (freezes, white screen, requires force-quit) when switching from English input method to Chinese IME (WeChat Input / 微信输入法) while typing inside WSL.

Key observations:

  • Typing in exclusively English IME works fine.
  • Typing in exclusively Chinese IME works fine.
  • The freeze happens only at the moment of switching from English IME to Chinese IME (or vice versa) after having typed some text.
  • The freeze occurs reliably with WeChat Input method. Other Chinese IMEs (Microsoft Pinyin, Sogou) likely affected as well.
  • The freeze is not limited to the /name scenario — it also happens in other contexts when switching IME while a TUI application is running.

Related Issues

This appears to be the same underlying class of bug as:

These are all manifestations of the same root issue: IME state transitions / input method switching triggers a deadlock (or infinite loop) in Warp's event processing pipeline.

To reproduce

  1. Windows 10/11 with Warp installed.
  2. Install WeChat Input Method (微信输入法) as a Chinese IME.
  3. Open Warp, enter WSL (wsl.exe).
  4. Run a TUI application that accepts text input (e.g., pi coding agent, nvim, tmux, etc.).
  5. Type a few characters in English (e.g., /name).
  6. Switch IME from English to Chinese (using Win+Space, language bar, or any other method).
  7. Result: Warp immediately freezes — the window goes white/unresponsive, and the process must be force-killed.

This can also be reproduced more directly without WSL:

  1. Open Warp on Windows (any shell: PowerShell, CMD, WSL).
  2. Press a shortcut that triggers IME/language switching (e.g., AutoHotkey script sending WM_INPUTLANGCHANGE, or using Win+Space).
  3. Warp freezes.

Expected behavior

Warp should handle IME switching gracefully without freezing, just like every other terminal emulator on Windows (Windows Terminal, ConEmu, etc.).

Technical analysis (from source code)

I examined the relevant source code and believe the root cause is one or both of:

1. std::sync::Mutex re-entrancy deadlock in winit's WNDPROC (Windows message handler)

In the Windows event loop, IME events from winit are handled in handle_ime_event(). The winit fork (at commit 7ef01853ae3fe952e6014080a88dc4352662dfb1) processes Windows IME messages in its WNDPROC callback in event_loop.rs:

WM_IME_STARTCOMPOSITION => {
    let ime_allowed = userdata.window_state_lock().ime_allowed;
    // ...
    userdata.send_event(Event::WindowEvent { event: WindowEvent::Ime(Ime::Enabled) });
}

The window_state field is Arc<Mutex<WindowState>> — a non-reentrant std::sync::Mutex. The event handler dispatched by send_event() flows into Warp's UI framework and may trigger calls back into winit (e.g., set_ime_position()ImmSetCompositionWindow), which can generate Windows messages synchronously. If those messages re-enter the WNDPROC and try to acquire window_state_lock(), the std::sync::Mutex deadlocks on the same thread.

2. LAYOUT_CACHE mutex + PeekMessageW re-entrancy

In keyboard.rs, next_kbd_msg() calls PeekMessageW():

pub fn next_kbd_msg(hwnd: HWND) -> Option<MSG> {
    let peek_retval = PeekMessageW(next_msg.as_mut_ptr(), hwnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE);

PeekMessageW can dispatch sent messages (via SendMessage from other threads) even when called with PM_NOREMOVE. If a sent message handler (e.g., from the IME) tries to acquire the same LAYOUT_CACHE mutex or window_state mutex while the current thread already holds it, deadlock.

3. IMM32 API re-entrancy

When IME is enabled, Warp calls set_ime_position() which invokes ImmSetCompositionWindow and ImmSetCandidateWindow. These IMM32 APIs can generate synchronous window messages that are processed immediately within the current stack frame, potentially causing re-entrant WNDPROC invocations.

Screenshots, videos, and logs

Will add if needed.

Operating system (OS)

Windows

Operating system and version

Windows 11

Shell Version

WSL2 (Ubuntu) + zsh

Current Warp version

Latest stable as of 2026-05-03

Regression

No, this bug or issue has existed throughout my experience using Warp

Does this block you from using Warp daily?

Yes, this issue prevents me from using Warp daily because I need to switch between English and Chinese when coding.

Is this an issue only in Warp?

Yes, I confirmed that this only happens in Warp, not other terminals (Windows Terminal works fine).

Suggested fix direction

  1. Replace std::sync::Mutex with a re-entrant mutex (e.g., parking_lot::ReentrantMutex) for window_state in winit's Windows platform, OR ensure the mutex is never held across any call that can process Windows messages.
  2. Ensure LAYOUT_CACHE mutex is not held when next_kbd_msg() is called, or use a re-entrant mutex there as well.
  3. Guard against re-entrant WNDPROC invocations by tracking re-entrancy depth (similar to the existing recurse_depth field in WindowData).

The existing recurse_depth field in WindowData suggests the developers are already aware of re-entrancy concerns in the Windows message handler. This IME switching scenario is likely hitting an unprotected re-entrant path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:terminal-inputTerminal command-line input, cursor movement, key handling, and input editing.area:ui-frameworkCore Warp UI framework, rendering, layout, and windowing infrastructure.bugSomething isn't working.duplicateThis issue or pull request already exists.os:windowsWindows-specific behavior, regressions, or requests.repro:highThe report includes enough evidence that the issue appears highly reproducible.triagedIssue has received an initial automated triage pass.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions