#10136·deskflow

macOS: client traps (SIGTRAP/dispatch_assert_queue) in OSXKeyState::pollActiveGroup() on forwarded key events — TIS main-queue assert, still unguarded on master

Author: ismailislerrCreated Sep 7, 2026Updated Sep 10, 2026
Labels:apple: mac:large_orange_diamond: pending response

Deskflow version info

Deskflow: 1.26.0.0
Qt: 6.10.1
System: macOS 26.5.2 (25F84), Apple Silicon (Mac16,10)

Build types

  • Official release (installer/package from GitHub releases)

Deskflow configuration

  • Windows server, macOS 26.5.2 client (Mac mini, Apple Silicon)
  • Client runs headless as a LaunchAgent (org.deskflow.client, KeepAlive=true), GUI not required
  • Single monitor per machine
  • Both systems report language tr (local languages: tr / remote languages: tr)

What steps will reproduce the problem?

  1. Windows server, macOS client, both with a Turkish (non-ABC) input source active.
  2. Connect the macOS client to the server.
  3. Switch to the macOS screen and type on the Windows keyboard.
  4. deskflow-core traps with EXC_BREAKPOINT (SIGTRAP). Because the client is a LaunchAgent with KeepAlive=true, launchd immediately respawns it, so the visible symptom is "the keyboard dies for a second and comes back" rather than an app disappearing.

The crash is intermittent, not every keystroke — it fires when HIToolbox needs to refresh its input-source list rather than serve it from cache. In one session it crashed 3 times within 3 minutes (19:15, 19:17, 19:17), then ran fine for 2 minutes.

The crash

Two distinct call sites, same root cause. The first one is not covered by #9924 — it is on the client, in the keystroke path:

A) OSXKeyState::pollActiveGroup() via KeyState::fakeKeyDown() — on every forwarded key event

Thread 5 CRASHED:
 0 libdispatch.dylib  _dispatch_assert_queue_fail + 120
 1 libdispatch.dylib  dispatch_assert_queue$V2.cold.1 + 116
 2 libdispatch.dylib  dispatch_assert_queue + 108
 3 HIToolbox          islGetInputSourceListWithAdditions + 160
 4 HIToolbox          isValidateInputSourceRef + 88
 5 HIToolbox          TSMGetInputSourceProperty + 36
 6 deskflow-core      OSXKeyState::pollActiveGroup() const + 40
 7 deskflow-core      KeyState::fakeKeyDown(unsigned int, unsigned int, unsigned short, std::string const&) + 252
 8 deskflow-core      ServerProxy::parseMessage(unsigned char const*) + 980
 9 deskflow-core      ServerProxy::handleData() + 188
10 deskflow-core      EventQueue::dispatchEvent(Event const&) + 332
11 deskflow-core      StreamFilter::filterEvent(Event const&) + 84
12 deskflow-core      EventQueue::dispatchEvent(Event const&) + 332
13 deskflow-core      EventQueue::loop() + 344
14 deskflow-core      App::runEventsLoop(void const*) + 24
15 deskflow-core      Thread::threadFunc(void*) + 128
16 deskflow-core      ArchMultithreadPosix::doThreadFunc(ArchThreadImpl*) + 76
17 deskflow-core      ArchMultithreadPosix::threadFunc(void*) + 56
18 libsystem_pthread  _pthread_start + 136
19 libsystem_pthread  thread_start + 8

B) AppUtilUnix::getKeyboardLayoutList() via ServerProxy construction — on connect

 0 libdispatch.dylib  _dispatch_assert_queue_fail + 120
 1 libdispatch.dylib  dispatch_assert_queue$V2.cold.1 + 116
 2 libdispatch.dylib  dispatch_assert_queue + 108
 3 HIToolbox          islGetInputSourceListWithAdditions + 160
 4 HIToolbox          TSMGetInputSourceCountWithFilteredAdditions + 40
 5 HIToolbox          TISCreateInputSourceList + 100
 6 deskflow-core      AppUtilUnix::getKeyboardLayoutList() + 132
 7 deskflow-core      ServerProxy::ServerProxy(Client*, deskflow::IStream*, IEventQueue*)

Variant B is the client-side mirror of #9924 (which was on the server, via ClientProxy1_8::synchronizeLanguages()).

Thread 0 is parked in -[NSApplication run] (runCocoaApp) in both cases — the main queue is alive and idle, the TIS call is simply made from EventQueue::loop()'s thread.

Why I'm filing this rather than commenting on #9924

#9924 was closed as not planned / cannot reproduce on macOS 27 beta 3. This report differs on three points:

  1. It reproduces on shipping macOS 26.5.2 (25F84), not a 27 beta. The main-queue enforcement on the TIS/TSM path is not exclusive to macOS 27.
  2. Call site A is new. #9924 only covers getKeyboardLayoutList(). OSXKeyState::pollActiveGroup() reaches TSMGetInputSourceProperty through isValidateInputSourceRef, and sits directly in fakeKeyDown() — so it is hit on forwarded key events, not just at connection time. Fixing AppUtilUnix.cpp alone would leave this path crashing.
  3. It is the client side; #9924 was the server side.

@amagus — in #9924 you asked for a full all-thread stack trace. Full .ips reports for 7 crashes are attached below; happy to provide a debug build trace or any other data.

Additional information

  • Not a regression — present since first use. This is a clean install, not an upgrade: Deskflow 1.26.0.0 was installed 2026-09-05 00:42 and the first crash is 2026-09-05 03:56, ~3 hours later. Both Deskflow.conf and Deskflow.conf.bak record lastVersion=1.26.0.0, so no earlier version ever ran here and I cannot claim an earlier release behaved differently. The macOS install itself has been unchanged since 2026-06-25 (SystemVersion.plist mtime; InstallHistory.plist shows only XProtect updates since), so this is not an OS-update side effect either.
  • Still unfixed on master. At a930c87ea4ec, OSXKeyState::pollActiveGroup() still guards its TISCopyCurrentKeyboardLayoutInputSource() / TISGetInputSourceProperty() pair with g_tisMutex alone. A mutex serialises Deskflow's own threads but cannot satisfy dispatch_assert_queue(main_queue), so the failing call is unchanged since the version I am running. The 2026-05-08 commit "fix(mac): protect TIS API calls with a mutex (they are not thread safe)" addresses thread-safety, which is a different constraint from the queue-affinity one that traps here.
  • 7 crash reports, all EXC_BREAKPOINT (SIGTRAP) / dispatch_assert_queue: 4 on 2026-09-05 (2× variant B, 2× variant A), 3 on 2026-09-07 (all variant A).
  • Does it stop me using Deskflow? Not entirely — KeepAlive masks it — but typing on the Mac from the Windows keyboard is unreliable.
  • Restarting the client clears it only until the next refresh of the input-source list.
  • Note on the sanity checks: this is the official 1.26.0.0 release and I have not run a continuous build. Rather than guess, I read the current source instead — see the master note above; the crashing call site is unchanged, so a newer build should not be expected to behave differently. Happy to run one and confirm if that would still be useful.
  • On the suggested fix — I note @amagus' comment in #9924 that "using the main queue is not an option on several of the TIS use cases". Call site A runs per-keystroke, so a dispatch_sync to the main queue there would also be a latency concern. Caching the active group and invalidating it from a main-queue kTISNotifySelectedKeyboardInputSourceChanged observer may fit better than dispatching per keystroke.

Show log

ceylon
[2026-09-07T19:17:42.165] NOTE: configured 1 server address(es)
[2026-09-07T19:17:42.179] NOTE: started client
[2026-09-07T19:17:42.179] IPC: connecting to '<server>': <server>:24800
2026-09-07 19:17:42.206 deskflow-core[27315:520335] starting cocoa loop
[2026-09-07T19:17:42.249] IPC: peer fingerprint: <redacted>
[2026-09-07T19:17:42.250] INFO: connected to secure socket
[2026-09-07T19:17:42.250] INFO: server tls certificate info: /CN=Deskflow
[2026-09-07T19:17:42.250] INFO: network encryption protocol: TLSv1.3
[2026-09-07T19:17:42.270] INFO: local languages: tr
[2026-09-07T19:17:42.275] INFO: remote languages: tr
[2026-09-07T19:17:42.281] WARNING: cursor may not be visible
[2026-09-07T19:17:42.283] IPC: connected to server
[2026-09-07T19:17:55.316] INFO: entering screen
[2026-09-07T19:17:55.319] INFO: clipboard was updated
[2026-09-07T19:17:55.321] INFO: clipboard was updated
                                    <-- crash here, launchd respawns
initial settings file: /Users/<user>/Library/Deskflow/Deskflow.conf
[2026-09-07T19:17:59.569] NOTE: configured 1 server address(es)
[2026-09-07T19:17:59.583] NOTE: started client
[2026-09-07T19:17:59.584] IPC: connecting to '<server>': <server>:24800
2026-09-07 19:17:59.609 deskflow-core[27316:520671] starting cocoa loop
[2026-09-07T19:17:59.651] INFO: connected to secure socket
[2026-09-07T19:17:59.676] INFO: local languages: tr
[2026-09-07T19:17:59.681] INFO: remote languages: tr
[2026-09-07T19:17:59.688] IPC: connected to server
[2026-09-07T19:18:27.470] INFO: entering screen