Skip to content

fix: stop the typing profiler crashing on non-key events - #225

Merged
arzafran merged 1 commit into
mainfrom
fix/183-typing-profiler-crash
Jul 31, 2026
Merged

fix: stop the typing profiler crashing on non-key events#225
arzafran merged 1 commit into
mainfrom
fix/183-typing-profiler-crash

Conversation

@arzafran

Copy link
Copy Markdown
Member

Refs #183. A real crash, found by trying to use the instrumentation.

The bug

TypingProfiler.swift's eventFields read event.keyCode, .modifierFlags and .isARepeat unconditionally. Those are only valid on key events — AppKit raises NSInternalInconsistencyException ("Invalid message sent to event") for any other type, and an uncaught ObjC exception terminates the process.

A KitDefined event (subtype 4) reaches it from insertText's defer during interpretKeyEvents, so with the profiler enabled the app dies mid-keystroke:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
    reason: 'Invalid message sent to event "NSEvent: type=KitDefined ... subtype=4"'
     3  AppKit  -[NSEvent keyCode]
     6  GhosttyNSView.insertText(_:replacementRange:) $deferL_
    16  -[NSView interpretKeyEvents:]
    17  GhosttyNSView.keyDown(with:)

The instrumentation crashed the app it was measuring. Only while switched on, which is why nothing caught it until someone tried to use it.

How it surfaced

The #183 refresh-cost step (#223) sets PROGRAMA_TYPING_TIMING_LOGS=1 so the in-process sampler records. All four dispatched measurement runs died here.

The existing lag harness never hit it because it sends an arrow key, which produces no committed text and so never enters insertText. The whole reason the refresh-cost work exists is to exercise the text-input path — and the first thing it exercised was this.

That also means the profiler has likely been unusable for anyone doing typing-latency work for as long as this has been there.

The fix

Read the key-only fields only for key events. flagsChanged keeps keyCode (valid there) but not isARepeat.

Test plan

  • xcodebuild -scheme programa** BUILD SUCCEEDED **, zero error: (verified from log contents)
  • CI green
  • After merge: re-dispatch the refresh-cost step and get past the crash to actual numbers

No regression test: reproducing it needs a live KitDefined event arriving during interpretKeyEvents with the profiler enabled, which is not reachable from a unit test. Per CLAUDE.md's policy that is a reason to say so rather than to add a source-shape test that would assert nothing about behaviour.

eventFields read event.keyCode, .modifierFlags and .isARepeat unconditionally.
Those are only valid on key events; AppKit raises
NSInternalInconsistencyException ("Invalid message sent to event") for any other
type, and an uncaught ObjC exception terminates the process.

A KitDefined event (subtype 4) reaches this from insertText's defer during
interpretKeyEvents, so with the profiler enabled the app dies mid-keystroke:

  *** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
  reason: 'Invalid message sent to event "NSEvent: type=KitDefined ... subtype=4"'
      3  AppKit  -[NSEvent keyCode]
      6  GhosttyNSView.insertText(_:replacementRange:) $deferL_
     16  -[NSView interpretKeyEvents:]
     17  GhosttyNSView.keyDown(with:)

The instrumentation crashed the app it was measuring, and only while switched
on -- which is why nothing caught it until someone tried to use it. Found by the
#183 refresh-cost step, whose four runs all died here; the lag harness never hit
it because an arrow key produces no committed text and so never enters
insertText.

Reads the key-only fields only for key events. flagsChanged keeps keyCode, which
is valid there, but not isARepeat.

Refs #183
@arzafran
arzafran merged commit 0919339 into main Jul 31, 2026
10 checks passed
@arzafran
arzafran deleted the fix/183-typing-profiler-crash branch July 31, 2026 01:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant