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-208GitHub issuePublicReceived

Apple Silicon: GRUB migrations make encrypted (and btrfs) installs unbootable

Reported by severian-commits · filed Sep 22, 2026Closed upstream on 2026-10-08 by the bot omarchybot, as not planned.

Received and recorded verbatim. Nothing has been checked yet.

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?
Not yet mapped to any requirement or component.
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?
Our staff decide whether the report is valid. Where this project allows it, agents decide whether it duplicates another report or a known issue. No decision has been recorded yet.

Original report

Apple Silicon: GRUB migrations make encrypted (and btrfs) installs unbootablerevision 1 · captured 2026-09-28 21:23 UTC via poll

System details

M1 MacBook (Apple Silicon), Asahi/Arch Linux ARM, Omarchy 4.0.4 (omarchy-dev r7060.g2a47d45), LUKS2 + btrfs, busybox mkinitcpio

What's wrong?

Summary

Two independent bugs in the Apple Silicon GRUB migrations each leave the machine unable to boot after omarchy-update:

  1. Migration `1790003445` ("Quiet the GRUB boot on Apple Silicon") overwrites `GRUB_CMDLINE_LINUX_DEFAULT` wholesale. The installer puts cryptdevice=… and rootflags=subvol=@ in that key, so both are deleted. The regenerated grub.cfg has no cryptdevice=, the encrypt hook never prompts, and boot drops to the mkinitcpio emergency shell with device 'UUID=<btrfs uuid>' not found.
  2. `install/hardware/apple/grub-console.sh` (migrations `1790030337` and `1790037110`) appends `rootflags=x-systemd.device-timeout=0` to `GRUB_CMDLINE_LINUX`. The Apple Silicon image boots a busybox mkinitcpio initramfs, not systemd, and its parser keeps only the last rootflags=. grub-mkconfig emits rootflags=subvol=@ first, so the appended option replaces it. The root filesystem then mounts at the btrfs top level (subvolid 5) instead of @, and there is no init to run. This affects every Apple Silicon btrfs install, encrypted or not. The option also has no effect without systemd in the initramfs.

Environment

  • M1 MacBook, Omarchy on Asahi (Arch Linux ARM), LUKS2 root with btrfs inside, busybox mkinitcpio (HOOKS=(base asahi udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt filesystems fsck))
  • omarchy-dev 4.0.4.r7060.g2a47d45-1, asahi-scripts 20260127.1-1, grub 2:2.14-1.1, mkinitcpio 42-1
  • /boot is the ESP; GRUB is regenerated through Asahi's update-grub → grub-mkconfig

Bug 1: quiet-boot migration deletes the installer's cmdline

/etc/default/grub as installed (backup /etc/default/grub.bak.20260910165426):

GRUB_CMDLINE_LINUX_DEFAULT="cryptdevice=UUID=<luks-uuid>:root:allow-discards rootflags=subvol=@ loglevel=3 quiet"
GRUB_CMDLINE_LINUX=""

1790003445.sh runs:

set_assignment GRUB_CMDLINE_LINUX_DEFAULT "$wanted_cmdline"   # fixed string, replaces the whole value
sudo update-grub

Afterwards:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash loglevel=0 systemd.show_status=false rd.udev.log_level=0 vt.global_cursor_default=0"
GRUB_CMDLINE_LINUX=""

Resulting kernel command line (no cryptdevice=):

BOOT_IMAGE=/vmlinuz-linux-asahi root=UUID=<btrfs-uuid> rw rootflags=subvol=@ quiet splash loglevel=0 …

On the next boot there is no passphrase prompt and you land in [rootfs ~]#. Manual recovery: cryptsetup open /dev/nvme0n1p5 root && mount -o rw,subvol=@ /dev/mapper/root /sysroot && exit.

Bug 2: rootflags=x-systemd.device-timeout=0 replaces subvol=@

grub-console.sh:

device_wait='rootflags=x-systemd.device-timeout=0'
…
grub_console_set GRUB_CMDLINE_LINUX "${cmdline:+$cmdline }$device_wait"

Generated linux line:

linux /vmlinuz-linux-asahi root=UUID=<btrfs-uuid> rw rootflags=subvol=@ cryptdevice=… rootflags=x-systemd.device-timeout=0 quiet splash …

mkinitcpio's parse_cmdline_item runs eval "$key"='${value:-y}' for every parameter, so the last value wins, and mount_handler runs mount -o "${rwopt},${rootflags}" with rootflags=x-systemd.device-timeout=0. The btrfs default subvolume is ID 5 (btrfs subvolume get-default / → ID 5 (FS_TREE)), so /new_root holds @, @home, @log… rather than a root filesystem.

Suggested fixes

  • 1790003445 / the finalizer: edit only the tokens being changed, e.g. remove loglevel=3 and add the quiet flags, instead of assigning a fixed string. Or move the installer's cryptdevice= and rootflags=subvol=@ into GRUB_CMDLINE_LINUX, where they belong because they're needed in every entry, recovery included. Before any update-grub, refuse to regenerate if the root is on LUKS and no cryptdevice=/rd.luks.* survives.
  • grub-console.sh: drop rootflags=x-systemd.device-timeout=0 on busybox initramfs. For a busybox init, the root-wait equivalent is rootwait or rootdelay=. If it has to stay, merge it into the existing flags (rootflags=subvol=@,x-systemd.device-timeout=0) rather than adding a second rootflags=.
  • Since both bugs only show at the next reboot, a post-update check that every linux line has the unlock option and that its last rootflags= contains subvol= would have caught each of them. I have one running locally (described below) and I'm happy to contribute it.

Local workaround

GRUB_CMDLINE_LINUX="cryptdevice=UUID=<luks-uuid>:root rootflags=x-systemd.device-timeout=0 rootflags=subvol=@"

grub-console.sh finds its token and leaves the line alone, and subvol=@ stays last. Then run sudo grub-mkconfig -o /boot/grub/grub.cfg. I also run a guard (verify-boot-unlock) from a pacman PostTransaction hook and from a systemd .path unit on /boot/grub/grub.cfg. The path unit is needed because these migrations regenerate GRUB outside any pacman transaction, so a pacman hook alone never sees the change.

Related

#7222 is the same class of mismatch (a systemd-style option on a busybox encrypt initramfs) on the Quattro upgrade path, but through rd.luks.name rather than these GRUB migrations.

View raw text
### System details

M1 MacBook (Apple Silicon), Asahi/Arch Linux ARM, Omarchy 4.0.4 (omarchy-dev r7060.g2a47d45), LUKS2 + btrfs, busybox mkinitcpio

### What's wrong?

## Summary

Two independent bugs in the Apple Silicon GRUB migrations each leave the machine unable to boot after `omarchy-update`:

1. **Migration `1790003445` ("Quiet the GRUB boot on Apple Silicon") overwrites `GRUB_CMDLINE_LINUX_DEFAULT` wholesale.** The installer puts `cryptdevice=…` and `rootflags=subvol=@` in that key, so both are deleted. The regenerated `grub.cfg` has no `cryptdevice=`, the `encrypt` hook never prompts, and boot drops to the mkinitcpio emergency shell with `device 'UUID=<btrfs uuid>' not found`.
2. **`install/hardware/apple/grub-console.sh` (migrations `1790030337` and `1790037110`) appends `rootflags=x-systemd.device-timeout=0` to `GRUB_CMDLINE_LINUX`.** The Apple Silicon image boots a busybox mkinitcpio initramfs, not systemd, and its parser keeps only the **last** `rootflags=`. grub-mkconfig emits `rootflags=subvol=@` first, so the appended option replaces it. The root filesystem then mounts at the btrfs top level (subvolid 5) instead of `@`, and there is no init to run. This affects **every** Apple Silicon btrfs install, encrypted or not. The option also has no effect without systemd in the initramfs.

## Environment

- M1 MacBook, Omarchy on Asahi (Arch Linux ARM), LUKS2 root with btrfs inside, busybox mkinitcpio (`HOOKS=(base asahi udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt filesystems fsck)`)
- `omarchy-dev 4.0.4.r7060.g2a47d45-1`, `asahi-scripts 20260127.1-1`, `grub 2:2.14-1.1`, `mkinitcpio 42-1`
- `/boot` is the ESP; GRUB is regenerated through Asahi's `update-grub` → `grub-mkconfig`

## Bug 1: quiet-boot migration deletes the installer's cmdline

`/etc/default/grub` as installed (backup `/etc/default/grub.bak.20260910165426`):

```
GRUB_CMDLINE_LINUX_DEFAULT="cryptdevice=UUID=<luks-uuid>:root:allow-discards rootflags=subvol=@ loglevel=3 quiet"
GRUB_CMDLINE_LINUX=""
```

`1790003445.sh` runs:

```bash
set_assignment GRUB_CMDLINE_LINUX_DEFAULT "$wanted_cmdline"   # fixed string, replaces the whole value
sudo update-grub
```

Afterwards:

```
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash loglevel=0 systemd.show_status=false rd.udev.log_level=0 vt.global_cursor_default=0"
GRUB_CMDLINE_LINUX=""
```

Resulting kernel command line (no `cryptdevice=`):

```
BOOT_IMAGE=/vmlinuz-linux-asahi root=UUID=<btrfs-uuid> rw rootflags=subvol=@ quiet splash loglevel=0 …
```

On the next boot there is no passphrase prompt and you land in `[rootfs ~]#`. Manual recovery: `cryptsetup open /dev/nvme0n1p5 root && mount -o rw,subvol=@ /dev/mapper/root /sysroot && exit`.

## Bug 2: `rootflags=x-systemd.device-timeout=0` replaces `subvol=@`

`grub-console.sh`:

```bash
device_wait='rootflags=x-systemd.device-timeout=0'
…
grub_console_set GRUB_CMDLINE_LINUX "${cmdline:+$cmdline }$device_wait"
```

Generated `linux` line:

```
linux /vmlinuz-linux-asahi root=UUID=<btrfs-uuid> rw rootflags=subvol=@ cryptdevice=… rootflags=x-systemd.device-timeout=0 quiet splash …
```

mkinitcpio's `parse_cmdline_item` runs `eval "$key"='${value:-y}'` for every parameter, so the last value wins, and `mount_handler` runs `mount -o "${rwopt},${rootflags}"` with `rootflags=x-systemd.device-timeout=0`. The btrfs default subvolume is ID 5 (`btrfs subvolume get-default /` → `ID 5 (FS_TREE)`), so `/new_root` holds `@`, `@home`, `@log`… rather than a root filesystem.

## Suggested fixes

- **1790003445 / the finalizer:** edit only the tokens being changed, e.g. remove `loglevel=3` and add the quiet flags, instead of assigning a fixed string. Or move the installer's `cryptdevice=` and `rootflags=subvol=@` into `GRUB_CMDLINE_LINUX`, where they belong because they're needed in every entry, recovery included. Before any `update-grub`, refuse to regenerate if the root is on LUKS and no `cryptdevice=`/`rd.luks.*` survives.
- **grub-console.sh:** drop `rootflags=x-systemd.device-timeout=0` on busybox initramfs. For a busybox init, the root-wait equivalent is `rootwait` or `rootdelay=`. If it has to stay, merge it into the existing flags (`rootflags=subvol=@,x-systemd.device-timeout=0`) rather than adding a second `rootflags=`.
- Since both bugs only show at the next reboot, a post-update check that every `linux` line has the unlock option and that its last `rootflags=` contains `subvol=` would have caught each of them. I have one running locally (described below) and I'm happy to contribute it.

## Local workaround

```
GRUB_CMDLINE_LINUX="cryptdevice=UUID=<luks-uuid>:root rootflags=x-systemd.device-timeout=0 rootflags=subvol=@"
```

`grub-console.sh` finds its token and leaves the line alone, and `subvol=@` stays last. Then run `sudo grub-mkconfig -o /boot/grub/grub.cfg`. I also run a guard (`verify-boot-unlock`) from a pacman `PostTransaction` hook and from a systemd `.path` unit on `/boot/grub/grub.cfg`. The path unit is needed because these migrations regenerate GRUB outside any pacman transaction, so a pacman hook alone never sees the change.

## Related

#7222 is the same class of mismatch (a systemd-style option on a busybox `encrypt` initramfs) on the Quattro upgrade path, but through `rd.luks.name` rather than these GRUB migrations.

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.

No decision has been recorded yet.