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-5290GitHub issuePublicDecided· Out of scope

Audio output switch OSD shows (null) for sinks with non-ASCII names (emoji, em dash)

Reported by roehrbacher · filed Oct 10, 2026 · open at source

Decided: Out of scope — decided by agents · verified 2 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

Audio output switch OSD shows (null) for sinks with non-ASCII names (emoji, em dash)revision 1 · captured 2026-10-10 09:24 UTC via poll

System details

Omarchy 4.0.4 on two machines (Dell XPS 14 with Intel Panther Lake, and a desktop with Ryzen 7 7700 / RX 9060 XT). PipeWire with pipewire-pulse, pactl 17.0-98-gb096.

What's wrong?

When switching audio outputs with omarchy-audio-output-switch (Shift + Mute), the OSD shows (null) instead of the device name for any sink whose description contains non-ASCII characters. Switching itself works, only the name is wrong. I see it on both machines with a Bluetooth headphone named 🕺🏽Bose and with a filter sink called Calibrated Speakers — Protected (em dash).

Steps to reproduce

  1. Give a Bluetooth audio device a name with an emoji (or use any sink with a non-ASCII description) and connect it.
  2. Press Shift + Mute until that output is selected.
  3. The OSD shows (null).

Cause

The script reads the name with:

next_sink_description=$(jq -r '.description // .properties."device.description" // .name' <<<"$next_sink")

pactl -f json can't escape non-ASCII. It prints Invalid ASCII character: 0xffffffe2 to stderr and emits the literal string "(null)" for description and device.description. Since that's a real string, the // fallbacks never kick in.

This looks like a regression: #1695 and #2205 reported the same thing and #1859 fixed it with a (null) check, but that check went away when the script was rewritten in 1eab0cff ("Integrate swaybg and swayosd into the new shell"). Upstream PulseAudio fixed the JSON escaping (pulseaudio#1310), but it isn't in a tagged release yet (latest is still v17.0). As far as I can see, this script is the only place in Omarchy that reads names from pactl -f json; the audio panel shows the names correctly.

Suggested fix

Read the description from pw-dump, which keeps UTF-8 intact, and fall back to the sink name:

sink_description() {
  local d
  d=$(pw-dump 2>/dev/null | jq -r --arg n "$1" \
    'first(.[] | select(.type == "PipeWire:Interface:Node" and .info.props."node.name" == $n) | .info.props."node.description") // empty')
  [[ -n $d && $d != "(null)" ]] && { echo "$d"; return; }
  echo "$1"
}

next_sink_description=$(sink_description "$next_sink_name")

The smaller option would be to treat "(null)" as missing again, but then the OSD shows the raw bluez_output... name. I'm running the pw-dump version locally and it works on both machines.

View raw text
### System details

Omarchy 4.0.4 on two machines (Dell XPS 14 with Intel Panther Lake, and a desktop with Ryzen 7 7700 / RX 9060 XT). PipeWire with pipewire-pulse, `pactl 17.0-98-gb096`.

### What's wrong?

When switching audio outputs with `omarchy-audio-output-switch` (Shift + Mute), the OSD shows `(null)` instead of the device name for any sink whose description contains non-ASCII characters. Switching itself works, only the name is wrong. I see it on both machines with a Bluetooth headphone named `🕺🏽Bose` and with a filter sink called `Calibrated Speakers — Protected` (em dash).

**Steps to reproduce**

1. Give a Bluetooth audio device a name with an emoji (or use any sink with a non-ASCII description) and connect it.
2. Press Shift + Mute until that output is selected.
3. The OSD shows `(null)`.

**Cause**

The script reads the name with:

```bash
next_sink_description=$(jq -r '.description // .properties."device.description" // .name' <<<"$next_sink")
```

`pactl -f json` can't escape non-ASCII. It prints `Invalid ASCII character: 0xffffffe2` to stderr and emits the literal string `"(null)"` for `description` and `device.description`. Since that's a real string, the `//` fallbacks never kick in.

This looks like a regression: #1695 and #2205 reported the same thing and #1859 fixed it with a `(null)` check, but that check went away when the script was rewritten in 1eab0cff ("Integrate swaybg and swayosd into the new shell"). Upstream PulseAudio fixed the JSON escaping (pulseaudio#1310), but it isn't in a tagged release yet (latest is still v17.0). As far as I can see, this script is the only place in Omarchy that reads names from `pactl -f json`; the audio panel shows the names correctly.

**Suggested fix**

Read the description from `pw-dump`, which keeps UTF-8 intact, and fall back to the sink name:

```bash
sink_description() {
  local d
  d=$(pw-dump 2>/dev/null | jq -r --arg n "$1" \
    'first(.[] | select(.type == "PipeWire:Interface:Node" and .info.props."node.name" == $n) | .info.props."node.description") // empty')
  [[ -n $d && $d != "(null)" ]] && { echo "$d"; return; }
  echo "$1"
}

next_sink_description=$(sink_description "$next_sink_name")
```

The smaller option would be to treat `"(null)"` as missing again, but then the OSD shows the raw `bluez_output...` name. I'm running the pw-dump version locally and it works on both machines.

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-10 12:55 UTC