Diagnosing system-wide scroll lag on macOS

After my Mac had been running for a few days, scrolling developed a small but noticeable delay. This happened in every app: I would start a two-finger gesture, nothing would move for a moment, and then the content would catch up.

I’d already done a restart last week when I ran into the same issue and it seemed to fix things. I assumed it had something to do with all the agent processes I was running all over the place. I stopped those but it didn’t fix it so turned to Codex for help. This is what it found:

Root cause

The machine was running the exact combination described in this Karabiner-Elements issue:

  • macOS 26.5.2, build 25F84
  • Karabiner-Elements 16.1.0
  • several days of uptime and sleep/wake cycles

Karabiner uses Core Graphics event taps to inspect input. A bug in 16.1.0 could leave old taps registered with WindowServer after sleep and reconnection. Even though almost all of the taps were disabled, WindowServer still had to traverse them while dispatching input events. That produced the delay before scrolling began.

Diagnosis

CGGetEventTapList was used to count taps by their owning process:

count-event-taps.swift
import CoreGraphics
import Foundation
var capacity: UInt32 = 0
guard CGGetEventTapList(0, nil, &capacity) == .success else {
exit(1)
}
let taps = UnsafeMutablePointer<CGEventTapInformation>.allocate(
capacity: Int(capacity)
)
defer { taps.deallocate() }
var actual = capacity
guard CGGetEventTapList(capacity, taps, &actual) == .success else {
exit(2)
}
var grouped: [pid_t: (total: Int, enabled: Int)] = [:]
for index in 0..<Int(actual) {
let tap = taps[index]
let current = grouped[tap.tappingProcess] ?? (0, 0)
grouped[tap.tappingProcess] = (
current.total + 1,
current.enabled + (tap.enabled ? 1 : 0)
)
}
print("all_taps=\(actual)")
for (pid, counts) in grouped.sorted(by: {
$0.value.total > $1.value.total
}) {
print(
"pid=\(pid) total=\(counts.total) " +
"enabled=\(counts.enabled) " +
"disabled=\(counts.total - counts.enabled)"
)
}

The result was fairly conclusive:

all_taps=803
pid=851 total=782 enabled=1 disabled=781

PID 851 was the system Karabiner-Core-Service process: 782 of the machine’s 803 event taps belonged to Karabiner, and 781 of those were disabled.

Remediation

The immediate workaround is to restart only the affected service:

Terminal window
sudo launchctl kickstart -k \
system/org.pqrs.service.daemon.Karabiner-Core-Service

This avoids a full logout or reboot. The applied remediation was an update to the official Karabiner 16.1.93 beta, whose changelog includes a fix for CGEventTap leaks. The installer restarted the service, and the tap count immediately fell from 803 to 22. Scrolling became responsive again without restarting the Mac.

Takeaway

The Karabiner configuration was keyboard-only, with a single Caps Lock remapping, but the affected event tap also covered scroll-wheel and pointing-device events. A keyboard customization could therefore degrade system-wide scrolling after enough sleep/wake cycles. A second issue documents the same behavior with a keyboard-only configuration.


The bulk of this bug report and resolution was written by codex. I am publishing it in the hopes that others who run into this issue can find a resolution as I have. The agent was able to search the web, diagnose this problem, and resolve it giving the following prompt.

User

why after I run this computer for a while is there a slight laggy delay when I scroll before the content actually starts moving? this happens for all apps on the computer, generally