Voice dictation permanently freezes TUI: main thread blocked in synchronous CoreAudio call (AudioUnitSetProperty) while opening microphone

Status Open
Reported on v2.1.226
Maintainer reply None cached
Activity 0 comments · opened Sep 5, 2026

Summary

Holding Space to start voice dictation permanently freezes the entire TUI: the footer stays on "keep holding…" forever, no keystroke is processed, Ctrl+C does not recover, and the only way out is killing the process. sample shows the main thread blocked in a synchronous CoreAudio call with no timeout while opening the microphone. When the audio HAL is slow to respond (a third-party audio client had degraded coreaudiod state), that call never returns and the whole input loop dies with it.

This looks like the root cause behind #20476 (closed), which described the same symptom without a stack trace.

Environment

  • Claude Code 2.1.226 (native build, claude.exe via Homebrew)
  • macOS 26.6.2 (25G83), Apple Silicon (arm64)
  • Terminal.app, hold-to-talk mode (default Space binding), claude.ai account

Stack sample of the frozen process

100% of samples (1674/1674) on the main thread, blocked here:

1674 Thread  DispatchQueue_1: com.apple.main-thread (serial)
  ... claude.exe frames ...
  ??? (in .5ed67dedd7cb7578-0.node)          <- bundled native audio module
  ??? (in .5ed67dedd7cb7578-0.node)
  AudioUnitSetProperty (in AudioToolboxCore) + 484
  ??? (in CoreAudio)
  ??? (in CoreAudio)
  ??? (in CoreAudio)
  AudioDeviceGetProperty (in CoreAudio) + 204
  HALPlugIn::ObjectHasProperty(HALObject const&, AudioObjectPropertyAddress const&) const + 44
  HAL_HardwarePlugIn_ObjectHasProperty(AudioHardwarePlugInInterface**, unsigned int, AudioObjectPropertyAddress const*) + 480

The process sits in AudioUnitSetProperty → AudioDeviceGetProperty → HALPlugIn::ObjectHasProperty indefinitely (observed >10 minutes, 0% CPU, state S). Since this runs on the same thread that services terminal input, the TUI freezes completely — matching the "no spinner, completely unresponsive" reports in #20476.

Controlled reproduction

The freeze correlates with degraded CoreAudio daemon state caused by a long-running third-party audio client (an app with a per-app volume mixer that inserts itself into CoreAudio; coreaudiod had accumulated 10+ hours of CPU time). Space key hold was simulated with synthetic CGEvents carrying the autorepeat flag, so all three tests are identical at the input layer:

| Test | Conditions | Result |
|---|---|---|
| A | third-party audio-mixer app running for ~2 weeks | permanent freeze, stack above |
| B | no third-party audio clients | dictation works end-to-end (mic opens, transcribes, inserts) |
| C | same app freshly relaunched | dictation works — the bad HAL state builds up over time |

So the external app is the trigger, but the defect is in Claude Code: a hostile-or-slow audio HAL should never be able to hang the input loop.

Expected behavior

  • Open the audio device asynchronously (or on a worker thread) with a timeout.
  • On timeout, cancel dictation, show an error ("microphone unavailable"), and keep the TUI responsive.

Workarounds found

  • claude --continue after killing the frozen process restores the session.
  • Quitting/relaunching the offending audio client (or disabling its mixer feature) clears the HAL state and dictation works again.

Happy to provide the full sample output or run an instrumented build if useful.

View original on GitHub ↗