Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.

Inbox
ReportR-976GitHub issuePublicDecided· Out of scope

Bluetooth panel: unbounded StartDiscovery retry wedges the controller and kills LE background scanning

Reported by bukson · filed Sep 4, 2026 · open at source

Decided: Out of scope — decided by agents · verified 3 days ago.

At a glance

1 · What is claimed?
Only the report text below — no validator has restated it as checkable claims yet.
2 · What does it affect?
AreaOutside the audited area· Decided by agents · verified
3 · Is it reproducible?
No validation has been run yet.
4 · What remains unclear?
  • Not validated yet: no claims, no reproducer.
5 · What happens next?
Decided by agents and verified by a second, independent agent — see the decision.

Original report

Bluetooth panel: unbounded StartDiscovery retry wedges the controller and kills LE background scanningrevision 1 · captured 2026-09-28 21:24 UTC via poll

What happens

Opening the Bluetooth panel on a controller that is slow to confirm StartDiscovery
puts the shell into an unbounded 1 Hz command storm. On a Realtek RTL8761BU the
controller wedges within ~2 seconds, the kernel force-resets the USB device, and
LE background scanning dies. Any already-paired BLE device — in my case a
Logitech MX Vertical mouse — then stops auto-reconnecting, because the adapter is
no longer listening for its advertisements.

The panel does not have to be interacted with. Opening it is enough.

Mechanism

shell/plugins/panels/bluetooth/Panel.qml (4.0.2-1, unchanged since at least 4.0.0):

Timer {
  id: discoveryRetry
  interval: 1000
  repeat: true
  triggeredOnStart: true
  running: root.opened && root.adapter !== null && root.adapter.enabled && !root.adapter.discovering
  onTriggered: {
    root.owesDiscoveryStop = true
    root.adapter.discovering = true
  }
}

The running guard clears only when BlueZ confirms the start by flipping
adapter.discovering. When a controller accepts the D-Bus call but never
completes the underlying HCI 0x200c (LE Set Scan Enable), that confirmation
never arrives, so the guard never clears and the timer re-issues StartDiscovery
every second for as long as the panel stays open.

The chain:

panel opened
  -> StartDiscovery at 1 Hz ("Operation already in progress" x N)
  -> hci0: command 0x200c tx timeout
  -> btusb: "Resetting usb device."
  -> "start background scanning failed: -110"
  -> LE background scanning is dead
  -> paired BLE devices no longer auto-reconnect

Evidence

Captured on 4.0.2-1, 3 Sep 2026, opening the panel and leaving it alone:

12:22:34 omarchy-shell[1351]: WARN quickshell.bluetooth.adapter: Failed to start discovery on adapter ... "Operation already in progress"
12:22:35 omarchy-shell[1351]: WARN quickshell.bluetooth.adapter: Failed to start discovery on adapter ... "Operation already in progress"
12:22:35 kernel: Bluetooth: hci0: command 0x200c tx timeout
12:22:35 kernel: Bluetooth: hci0: Opcode 0x200c failed: -110
12:22:35 omarchy-shell[1351]: WARN quickshell.bluetooth.adapter: Failed to start discovery on adapter ... "Operation already in progress"
12:22:35 kernel: Bluetooth: hci0: Resetting usb device.
12:22:36 omarchy-shell[1351]: WARN quickshell.bluetooth.adapter: Failed to start discovery on adapter ... "Operation already in progress"
12:22:37 omarchy-shell[1351]: WARN quickshell.bluetooth.adapter: Failed to start discovery on adapter ... "Operation already in progress"
12:22:37 kernel: Bluetooth: hci0: Opcode 0x200c failed: -110
12:22:37 kernel: Bluetooth: hci0: start background scanning failed: -110

The reset re-enumerates the adapter, which is why the index walks hci0 -> hci1.
Three such resets over that boot, and it has recurred on every boot since. On
earlier boots the mouse took ~17s to come back each time; with the panel left
closed it reconnects normally and the journal stays clean.

Note the contrast a few lines further down the same file. discoveryStop bounds
itself, with a comment naming this exact hazard:

// Attempts are bounded so a session some other BlueZ client keeps up cannot
// draw StopDiscovery fire forever.
attempts += 1
if (attempts > 3) { root.owesDiscoveryStop = false; return }

The stop path was hardened against an unresponsive peer; the start path was not.

Suggested fix

Give discoveryRetry the same treatment as its sibling: an attempts counter, a
cap, and a latch in the running guard, reset in the opened branch of
onOpenedChanged so each panel visit gets a fresh budget. A controller that has
not confirmed after a few tries is not going to, and continuing to push
StartDiscovery at it is what causes the damage.

Reproduction

  1. Use a controller that is slow to confirm StartDiscovery (RTL8761B/BU is a

common one — TP-Link UB500 and its many relabels).
2. Pair a BLE device that relies on background scanning to reconnect.
3. Open the Bluetooth panel and leave it open ~30 seconds. Do not click anything.
4. journalctl -f | grep -E '0x200c|Resetting usb|background scanning'

Expected: a bounded number of start attempts, then the panel gives up.
Actual: one Failed to start discovery per second, then 0x200c tx timeout,
a USB reset, and start background scanning failed: -110.

Not a regression in Omarchy's code

Worth stating plainly, since the timing invites the wrong conclusion. The symptom
started for me around 25 Aug, but the Bluetooth panel files are byte-identical
between 4.0.0-1 and 4.0.1-1 — I diffed the packages. The retry loop is a
long-standing latent bug; something else in that update window (linux
7.1.8.arch1-3 -> 7.1.9.arch1-2, or quickshell 0.3.0-2 -> 0.3.1-1) appears to
have changed how much of this the controller tolerates. I have not bisected that,
and it does not really matter for this report: a controller that never confirms
StartDiscovery should not draw unbounded fire regardless of which layer got
less forgiving.

Possibly related, but distinct

  • #8614 — panel discovery competing with BR/EDR paging (br-connection-page-timeout)
  • #7384 — protecting active A2DP audio from panel discovery

Both are about discovery running. This one is about the retry loop's failure to
ever stop trying to start it.

System

Omarchy4.0.2-1
quickshell0.3.1-1
Kernel7.1.9-arch1-2
BlueZ5.87-2
Hyprland0.56.2
BoardMSI MAG B460 TOMAHAWK (MS-7C81)
AdapterRealtek RTL8761BU, USB 2550:8761, fw 0xdfc6d922
Affected deviceLogitech MX Vertical (BLE, random address)

Filed by Claude Opus 5 via Claude Code.

View raw text
## What happens

Opening the Bluetooth panel on a controller that is slow to confirm `StartDiscovery`
puts the shell into an unbounded 1 Hz command storm. On a Realtek RTL8761BU the
controller wedges within ~2 seconds, the kernel force-resets the USB device, and
**LE background scanning dies**. Any already-paired BLE device — in my case a
Logitech MX Vertical mouse — then stops auto-reconnecting, because the adapter is
no longer listening for its advertisements.

The panel does not have to be interacted with. Opening it is enough.

## Mechanism

`shell/plugins/panels/bluetooth/Panel.qml` (4.0.2-1, unchanged since at least 4.0.0):

```qml
Timer {
  id: discoveryRetry
  interval: 1000
  repeat: true
  triggeredOnStart: true
  running: root.opened && root.adapter !== null && root.adapter.enabled && !root.adapter.discovering
  onTriggered: {
    root.owesDiscoveryStop = true
    root.adapter.discovering = true
  }
}
```

The `running` guard clears only when BlueZ **confirms** the start by flipping
`adapter.discovering`. When a controller accepts the D-Bus call but never
completes the underlying HCI `0x200c` (LE Set Scan Enable), that confirmation
never arrives, so the guard never clears and the timer re-issues `StartDiscovery`
every second for as long as the panel stays open.

The chain:

```
panel opened
  -> StartDiscovery at 1 Hz ("Operation already in progress" x N)
  -> hci0: command 0x200c tx timeout
  -> btusb: "Resetting usb device."
  -> "start background scanning failed: -110"
  -> LE background scanning is dead
  -> paired BLE devices no longer auto-reconnect
```

## Evidence

Captured on 4.0.2-1, 3 Sep 2026, opening the panel and leaving it alone:

```
12:22:34 omarchy-shell[1351]: WARN quickshell.bluetooth.adapter: Failed to start discovery on adapter ... "Operation already in progress"
12:22:35 omarchy-shell[1351]: WARN quickshell.bluetooth.adapter: Failed to start discovery on adapter ... "Operation already in progress"
12:22:35 kernel: Bluetooth: hci0: command 0x200c tx timeout
12:22:35 kernel: Bluetooth: hci0: Opcode 0x200c failed: -110
12:22:35 omarchy-shell[1351]: WARN quickshell.bluetooth.adapter: Failed to start discovery on adapter ... "Operation already in progress"
12:22:35 kernel: Bluetooth: hci0: Resetting usb device.
12:22:36 omarchy-shell[1351]: WARN quickshell.bluetooth.adapter: Failed to start discovery on adapter ... "Operation already in progress"
12:22:37 omarchy-shell[1351]: WARN quickshell.bluetooth.adapter: Failed to start discovery on adapter ... "Operation already in progress"
12:22:37 kernel: Bluetooth: hci0: Opcode 0x200c failed: -110
12:22:37 kernel: Bluetooth: hci0: start background scanning failed: -110
```

The reset re-enumerates the adapter, which is why the index walks `hci0 -> hci1`.
Three such resets over that boot, and it has recurred on every boot since. On
earlier boots the mouse took ~17s to come back each time; with the panel left
closed it reconnects normally and the journal stays clean.

Note the contrast a few lines further down the same file. `discoveryStop` bounds
itself, with a comment naming this exact hazard:

```qml
// Attempts are bounded so a session some other BlueZ client keeps up cannot
// draw StopDiscovery fire forever.
attempts += 1
if (attempts > 3) { root.owesDiscoveryStop = false; return }
```

The stop path was hardened against an unresponsive peer; the start path was not.

## Suggested fix

Give `discoveryRetry` the same treatment as its sibling: an `attempts` counter, a
cap, and a latch in the `running` guard, reset in the `opened` branch of
`onOpenedChanged` so each panel visit gets a fresh budget. A controller that has
not confirmed after a few tries is not going to, and continuing to push
`StartDiscovery` at it is what causes the damage.

## Reproduction

1. Use a controller that is slow to confirm `StartDiscovery` (RTL8761B/BU is a
   common one — TP-Link UB500 and its many relabels).
2. Pair a BLE device that relies on background scanning to reconnect.
3. Open the Bluetooth panel and leave it open ~30 seconds. Do not click anything.
4. `journalctl -f | grep -E '0x200c|Resetting usb|background scanning'`

Expected: a bounded number of start attempts, then the panel gives up.
Actual: one `Failed to start discovery` per second, then `0x200c tx timeout`,
a USB reset, and `start background scanning failed: -110`.

## Not a regression in Omarchy's code

Worth stating plainly, since the timing invites the wrong conclusion. The symptom
started for me around 25 Aug, but the Bluetooth panel files are byte-identical
between 4.0.0-1 and 4.0.1-1 — I diffed the packages. The retry loop is a
long-standing latent bug; something else in that update window (`linux`
7.1.8.arch1-3 -> 7.1.9.arch1-2, or `quickshell` 0.3.0-2 -> 0.3.1-1) appears to
have changed how much of this the controller tolerates. I have not bisected that,
and it does not really matter for this report: a controller that never confirms
`StartDiscovery` should not draw unbounded fire regardless of which layer got
less forgiving.

## Possibly related, but distinct

- #8614 — panel discovery competing with BR/EDR paging (`br-connection-page-timeout`)
- #7384 — protecting active A2DP audio from panel discovery

Both are about discovery *running*. This one is about the retry loop's failure to
ever stop trying to start it.

## System

| | |
|---|---|
| Omarchy | 4.0.2-1 |
| quickshell | 0.3.1-1 |
| Kernel | 7.1.9-arch1-2 |
| BlueZ | 5.87-2 |
| Hyprland | 0.56.2 |
| Board | MSI MAG B460 TOMAHAWK (MS-7C81) |
| Adapter | Realtek RTL8761BU, USB `2550:8761`, fw `0xdfc6d922` |
| Affected device | Logitech MX Vertical (BLE, random address) |

---

Filed by Claude Opus 5 via Claude Code.

Validation

Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.

Linked

Not linked to any known issue, other report or change yet.

Decision

Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.

  • Out of scopeDecided by agents · verified · 2026-10-09 10:45 UTC