Skip to content

TUI-freeze-Windows-crossterm-poll #1812

@aboimpinto

Description

@aboimpinto

Summary

DeepSeek TUI v0.8.39 freezes intermittently on Windows 11. The UI becomes completely unresponsive — no keyboard input, no screen updates — but the process stays alive (not crashed). Two confirmed events captured with logs, session files, and thread-state analysis.

Freeze Event #1 — 2026-05-19 ~02:12 CEST

Trigger: Model ran pnpm build in a Next.js project. The 5KB build output (Prisma errors + Next.js route table with Unicode box-drawing characters) was fed back as a tool result. The model streamed a response for ~8 minutes (00:10–00:17 UTC). The TUI froze during or after this long streaming period. The model's response was never saved to the session file.

Session file: Captures pre-freeze state — 182 messages, last message is the pnpm build output. The model's reply (message 183) is missing.

Freeze Event #2 — 2026-05-19 ~08:50 CEST (diagnosed in detail)

Trigger: Five rapid exec_shell calls in 51 seconds:

  1. npm config get npm-globalconfig ... — failed
  2. set | findstr /i "npm_ jsr..." — failed
  3. Third npm investigation command — failed
  4. Fourth command — succeeded
  5. dir /s /b "%APPDATA%\npm\*npmrc*" ... — succeeded (97 bytes output)

The TUI froze after all five commands completed but before the model's streaming response (MessageStarted) was processed. The model never rendered any output.

Log evidence: Exact exec_shell calls matched by input_bytes size and timestamps to visible screen content. No MessageStarted was processed by the TUI event loop.

Thread-State Analysis (PID 141448, captured 5h post-freeze)

Metric Value
Threads 35 (28 at startup, 6 new threads created 5h later)
State Wait - UserRequest (main thread)
Windows Responding true (not flagged as hung)
Working set 81.5 MB

Key finding: The main thread is stuck in Wait - UserRequest, consistent with crossterm::event::poll()WaitForSingleObject(console_input_handle, INFINITE). The Windows console input handle has stopped delivering events. Meanwhile, the tokio runtime is still alive — it spawned 6 new worker threads 5 hours after the freeze, proving async code (engine, HTTP) continues to function.

Root Cause Hypothesis

Windows console input handle starvation after child process exit.

Each exec_shell call creates a child process via CreateProcess. On Windows, child processes can briefly attach to the parent's console. If a child exits while the console input buffer is in an inconsistent state, the parent's WaitForSingleObject on the console input handle may hang indefinitely — crossterm::event::poll() calls this internally and never returns.

This is consistent with:

  • Freeze happening right after rapid exec_shell calls
  • Main thread blocked at OS boundary, not in Rust code
  • Process otherwise healthy (tokio still running)
  • Windows-specific (Unix doesn't have this console input handle model)

Suggested Fix Directions

  1. Bounded event poll timeout: Instead of event::poll(INFINITE), use a short timeout (e.g., 100ms). If the poll consistently times out with no events for >5 seconds while the engine has pending work, force a terminal mode recovery: re-enable raw mode, re-arm event listening.

  2. Post-exec_shell console flush: After each exec_shell completes, call FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)) via windows-sys to clear any stale state left by the child process.

  3. Watchdog thread: Spawn a separate thread that monitors the event loop heartbeat. If no events are processed for >10 seconds, trigger terminal recovery or graceful shutdown.

Environment

  • OS: Windows 11
  • Terminal: Windows Terminal (WT_SESSION present)
  • DeepSeek TUI version: 0.8.39
  • Mode: YOLO (auto-approve)
  • Model: deepseek-v4-pro
  • Branch: feat/combined-local-build (local diagnostic logging added, not pushed)

Files Available

  • Log file with exact exec_shell timestamps and byte sizes
  • Session file (Event Fix cargo fmt formatting issues #1) with pre-freeze state
  • Frozen process still running (PID 141448) — can capture minidump with procdump -ma on request
  • Full investigation document with both event timelines

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or request

    Projects

    Status
    Backlog

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions