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

Notification icon slot renders a magenta placeholder instead of hiding when an icon fails to resolve

Reported by jpchabot · filed Aug 19, 2026 · open at source

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

Notification icon slot renders a magenta placeholder instead of hiding when an icon fails to resolverevision 1 · captured 2026-09-28 21:29 UTC via poll

System details

AMD Ryzen 7 7800X3D, NVIDIA RTX 4090 (nvidia 610.57.04), Omarchy 4.0.0-1, Hyprland 0.56.2, Quickshell 0.3.0 (quickshell-git, rev 28771c7c), qt6-base 6.11.1-1, kernel 7.1.8-arch1-3

What's wrong?

When a notification requests a themed icon that cannot be resolved, the icon slot renders a 2x2 magenta/black placeholder instead of being hidden.

Steps to reproduce

notify-send -i this-icon-does-not-exist-12345 "Test" "unresolvable icon name"

Expected: the icon slot is hidden, as the comment on NotificationCard.qml lines 117-118 intends.
Actual: a magenta/black checkerboard.

Why the existing guard cannot fire

shell/plugins/notifications/components/NotificationCard.qml line 119:

visible: !root.collapseRedundantIcon && !root.compactGlyph && (root.hasSmallIcon || root.hasGlyph) && (root.hasGlyph || smallIconImage.status !== Image.Error)

The comment above it states the intent: "prevents rendering Qt's pink broken-image placeholder".

However, Quickshell's image://icon/ provider logs a warning but still returns a valid placeholder image with status === Image.Ready. It never returns Image.Error, so the condition can never be true. Measured with a standalone Quickshell probe on this system:

image://icon/this-icon-does-not-exist-12345   sourceSize=40   ->  status Ready, 40x40 placeholder
image://icon/this-icon-does-not-exist-12345   sourceSize=0    ->  status Ready, 2x2 placeholder

The shell log at the same moment:

Could not load icon "this-icon-does-not-exist-12345" at size QSize(2, 2) from request
Could not load icon "this-icon-does-not-exist-12345" at size QSize(128, 128) from request

A 2x2 placeholder scaled into the 40px slot is the four-quadrant checkerboard seen on screen.

Separately, line 39 routes the image-path hint straight to Image.source, bypassing iconSource() and the Quickshell.iconPath(value, true) check that it applies to appIcon on line 63:

readonly property string smallIconSource: image.length > 0 ? image : iconSource(appIcon)

Suggested fix

Quickshell.iconPath(name, true) correctly returns "" for an unresolvable name. Validating through it before assigning Image.source -- including for the image-path hint on line 39 -- would let the existing hide-the-slot logic work, instead of depending on an Image.Error that never arrives.

How I encountered it (context, not the bug)

I first hit this with com.mitchellh.ghostty, whose icon is installed in ten sizes under /usr/share/icons/hicolor/. That turned out to be a stale icon cache rather than a missing icon: Ghostty was installed after my Quickshell process started, /usr/share/icons/hicolor/icon-theme.cache was regenerated afterward, and the long-running shell held a pre-install view of it. Icons already in the cache (vivaldi, folder, application-x-executable) resolved correctly throughout, and omarchy restart shell clears it. That part is not an Omarchy bug and is not what this issue reports.

It is only how I noticed the placeholder behaviour above, which reproduces on a freshly restarted shell with a clean cache using the notify-send command given earlier.

Related

#7203 reaches the same rendering defect from a different trigger -- an icon theme name (Yaru-gray) that is absent from disk. Fixing this guard would cover both.

View raw text
### System details

AMD Ryzen 7 7800X3D, NVIDIA RTX 4090 (nvidia 610.57.04), Omarchy 4.0.0-1, Hyprland 0.56.2, Quickshell 0.3.0 (quickshell-git, rev 28771c7c), qt6-base 6.11.1-1, kernel 7.1.8-arch1-3

### What's wrong?

When a notification requests a themed icon that cannot be resolved, the icon slot renders a 2x2 magenta/black placeholder instead of being hidden.

**Steps to reproduce**

```bash
notify-send -i this-icon-does-not-exist-12345 "Test" "unresolvable icon name"
```

Expected: the icon slot is hidden, as the comment on `NotificationCard.qml` lines 117-118 intends.
Actual: a magenta/black checkerboard.

### Why the existing guard cannot fire

`shell/plugins/notifications/components/NotificationCard.qml` line 119:

```qml
visible: !root.collapseRedundantIcon && !root.compactGlyph && (root.hasSmallIcon || root.hasGlyph) && (root.hasGlyph || smallIconImage.status !== Image.Error)
```

The comment above it states the intent: "prevents rendering Qt's pink broken-image placeholder".

However, Quickshell's `image://icon/` provider logs a warning but still returns a **valid** placeholder image with `status === Image.Ready`. It never returns `Image.Error`, so the condition can never be true. Measured with a standalone Quickshell probe on this system:

```
image://icon/this-icon-does-not-exist-12345   sourceSize=40   ->  status Ready, 40x40 placeholder
image://icon/this-icon-does-not-exist-12345   sourceSize=0    ->  status Ready, 2x2 placeholder
```

The shell log at the same moment:

```
Could not load icon "this-icon-does-not-exist-12345" at size QSize(2, 2) from request
Could not load icon "this-icon-does-not-exist-12345" at size QSize(128, 128) from request
```

A 2x2 placeholder scaled into the 40px slot is the four-quadrant checkerboard seen on screen.

Separately, line 39 routes the `image-path` hint straight to `Image.source`, bypassing `iconSource()` and the `Quickshell.iconPath(value, true)` check that it applies to `appIcon` on line 63:

```qml
readonly property string smallIconSource: image.length > 0 ? image : iconSource(appIcon)
```

### Suggested fix

`Quickshell.iconPath(name, true)` correctly returns `""` for an unresolvable name. Validating through it before assigning `Image.source` -- including for the `image-path` hint on line 39 -- would let the existing hide-the-slot logic work, instead of depending on an `Image.Error` that never arrives.

### How I encountered it (context, not the bug)

I first hit this with `com.mitchellh.ghostty`, whose icon **is** installed in ten sizes under `/usr/share/icons/hicolor/`. That turned out to be a stale icon cache rather than a missing icon: Ghostty was installed after my Quickshell process started, `/usr/share/icons/hicolor/icon-theme.cache` was regenerated afterward, and the long-running shell held a pre-install view of it. Icons already in the cache (`vivaldi`, `folder`, `application-x-executable`) resolved correctly throughout, and `omarchy restart shell` clears it. That part is not an Omarchy bug and is not what this issue reports.

It is only how I noticed the placeholder behaviour above, which reproduces on a freshly restarted shell with a clean cache using the `notify-send` command given earlier.

### Related

#7203 reaches the same rendering defect from a different trigger -- an icon theme name (`Yaru-gray`) that is absent from disk. Fixing this guard would cover both.

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 04:50 UTC