# 14. Troubleshooting ## The general moves **Get a console that is not sway.** `Ctrl+Alt+F2` through `F6` are virtual terminals. They are themed the same way and they work when the session does not. `Ctrl+Alt+F1` goes back to the greeter. **Read the logs.** journalctl -b -p err # this boot, errors and worse journalctl --user -b # your session's services journalctl -b -u greetd # the login screen **Reload sway** after editing its config: `Mod+Shift+C`. **Boot the previous image.** Hold `Esc` or `Shift` at boot for the GRUB menu and pick the older deployment. Nothing you do to the running system can take that away, which is the point of an atomic base. --- ## The session ### Nothing opens when I press Mod+Return Check the config's terminal name. `~/.config/sway/config` sets `$term shop`, and if that line has been edited to something the image does not carry, the binding runs nothing and says nothing. `shop` is built into the image rather than installed from a repo, so the package manager cannot tell you whether it is there. `command -v shop` from a virtual console can. Two ways out that do not need a terminal: `Mod+D` opens the launcher, and `Ctrl+Alt+F2` gets you a virtual console where you can edit `~/.config/sway/config` and log back in. ### An app exits saying it cannot open a display It is an X11 application, and there is no X server. See chapter 7: Alloy ships `xwayland disable`, and the way back is `xwayland enable` in `~/.config/sway/config.d/`. Try the Wayland flag first if it is an Electron app: org.example.SomeApp --ozone-platform=wayland ### I mistyped my password too many times and now it will not take the right one Fifty consecutive failures locks the account for 24 hours. From another session, or a virtual console logged in as another user: run0 faillock --user --reset `faillock --user ` on its own shows the count without clearing it. ### I edited the sway config and the session will not start Log in on a virtual console and check it: sway --validate Then fix the file, or move it aside to fall back to the shipped one: mv ~/.config/sway/config ~/.config/sway/config.broken alloy theme apply ### The screen locked and I cannot unlock it Type your password even if nothing is drawn; swaylock accepts input before it has anything to show. If the lock has genuinely crashed, switch to a virtual console and kill it: pkill swaylock That leaves an unlocked session, so do it only at a machine you trust. ### My session locks while I am watching a video Only a handful of applications hold the lock off, and only when fullscreen: mpv, imv, and the browser. Add yours in `~/.config/sway/config` next to the existing `inhibit_idle fullscreen` lines. A blanket rule is deliberately not shipped, because it would make walking away from a fullscreen terminal leave the machine unlocked. --- ## Hardware ### The brightness keys do nothing This one is silent by design of the underlying pieces, so check both halves: groups | grep video # your account is in the video group ls -l /sys/class/backlight/*/brightness # group-writable, group video Brightness is a direct write to a sysfs file. It takes a udev rule to make that file writable and your account being in the `video` group for the rule to grant anything. Either one alone leaves the keys dead with no error anywhere: the process that would have complained has nowhere to log. Volume keys use a different path entirely (PipeWire, no privilege), which is why one can work while the other does not. ### The volume overlay never appears `swayosd-server` is started by the sway config, not by a systemd unit. If it died, restart it: swayosd-server & ### Print Screen seems to do nothing It probably worked. Check `~/Pictures/Screenshots`. Every capture also raises a notification, so if you get neither the file nor the notification, run the script by hand to see the error: alloy-shot output ### A second monitor is not behaving This is the least tested part of the system. `swaymsg -t get_outputs` shows what sway sees, and `~/.config/sway/config.d/50-display.conf` is where to write `output` lines by hand. `alloy display` will not pick modes yet. --- ## The console ### alloy net cannot join a new network Connecting to a saved network needs no privilege; creating one does, and the console does not escalate yet. Use: run0 nmcli device wifi connect "Network Name" --ask ### alloy pkg or alloy update says it cannot read the system Those two tabs front `rpm-ostree`, which exists only on an ostree system. If you are running the console somewhere else, that message is correct rather than broken. ### The console will not start at all It needs a theme on its search path and fails loudly if there is none. Two verbs deliberately survive that, because they are on the login path: `alloy theme apply` and `alloy status --bar`. If the console is broken but the bar still draws, the theme directory is what to look at (`/usr/share/alloy/themes`). --- ## Appearance ### I switched to night and nothing changed The switch applies at the next login. Log out and back in, or run `alloy theme apply` and restart the affected programs. sway itself needs the re-login regardless, because it reads its config exactly once. ### alloy theme apply says it skipped my files It found a config that matches neither the day nor the night render, decided it was yours, and left it alone. That is the intended behaviour. If you want the shipped render back: alloy theme apply --force which keeps your version as a `.alloy-bak` beside it. ### Some characters render as boxes If they are emoji, that is expected: no emoji font is installed. Install any one and fontconfig picks it up with no further configuration. If they are not emoji, `fc-list :lang=` will say whether anything in the image covers that script. ### The browser is light when my desktop is dark System appearance reaches the browser through the desktop portal rather than through any file Alloy ships, and that path has not been verified on real hardware yet. If it does not work, set the theme in the browser's own settings; Alloy does not ship browser configuration to fix it with. --- ## Network access ### A service I started is unreachable from another machine Alloy refuses inbound connections it was not told to allow, so a server you started on a port is reachable from the machine itself and from nowhere else. See what is open: firewall-cmd --list-all Then allow yours, permanently: run0 firewall-cmd --permanent --add-port=8080/tcp run0 firewall-cmd --reload Two things that are not the firewall, checked before reaching for it. If the other machine is on your tailnet, the tailnet is exempt already, so a failure there is the service binding to localhost rather than to every interface. And a server profile does not answer mDNS, so `.local` failing while the IP address works is chapter 12 rather than a firewall rule. ### SSH says permission denied, and I know the password is right The password is not the problem. Alloy accepts a key and nothing else: `PasswordAuthentication` is off, so is the keyboard-interactive path behind it, and root is key-only. A correct password gets the same refusal a wrong one does. If you can reach a console on the machine, add your key there. Chapter 3, "Adding a key after the fact", is the four lines. If you cannot reach a console, this is the case with no remote fix. A headless machine installed with no key has no way in, and the way back is a screen, a keyboard, or a reinstall from a medium with a key baked into it. ### I added a key and it still refuses Check the modes. sshd will not read an `authorized_keys` that anyone but its owner can write, and it declines without telling the client why: chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys Then check the file holds the **public** half, one key per line, starting with something like `ssh-ed25519`. The reason for a refusal is always in the server's journal even when the client is told nothing: journalctl -u sshd -n 50 ## Disks and boot ### The machine asks for a passphrase it never asked for before The TPM stopped answering: it was cleared, the board changed, or the disk moved to another machine. Type the passphrase you set at install. If you do not have it, this is what the eight-word recovery phrase from the installer is for. Without either one, the data is gone. That is what encryption means. ### I have my password store but nothing will decrypt Two separate secrets get needed at the same moment, when a machine is lost, and they are easy to conflate. The eight-word recovery phrase above unlocks the **disk**. The age identity under `~/.config/gopass/age/` decrypts the **password store**. Neither one substitutes for the other, and neither is in the git repository holding the store, by design. So a clone of the store on a new machine is ciphertext until you put the identity back. If you still have the old disk, copy it off. If you kept a copy somewhere off the machine, restore that. If neither, the store is gone the same way an encrypted disk with no phrase is gone. Worth doing before you need it: keep the identity somewhere that is not the machine and not the store's remote. Chapter 10 covers where it lives and why it never travels with the ciphertext. ### The new image is worse than the old one rpm-ostree rollback systemctl reboot Or pick the previous entry in the GRUB menu at boot. See chapter 8. ### I layered a package and now the system will not boot Boot the previous deployment from the GRUB menu, then remove it: rpm-ostree uninstall Layered packages are the most common way to break an otherwise reliable base, which is the argument in chapter 7 for putting things in boxes instead. ### The machine came up with no console, and nothing will layer The symptom set is distinctive: no `alloy` and no terminal after the first boot following an install, `rpm-ostree status` failing with `Could not activate remote peer`, and `systemctl --failed` naming `alloy-layer-components.service`. Nothing in the journal explains any of it. Only machines installed from an older image have this. Their installer wrote six files in `/etc` without asking the policy what they should be labelled, one of them being the lock systemd needs to run a service under a dynamic user. `rpm-ostreed` is such a service, so the machine cannot layer a package at all, and the components that make it usable are layered at first boot. One command fixes it, from a virtual console, with no reinstall: sudo restorecon -R /etc systemctl reboot Confirm it afterwards, from a checkout of the repository: sudo build/check-installed.sh An install from a current image does not need any of this. The installer relabels the target itself now, and the check above passes on a fresh machine. --- ## Diagnostics that are off by default Alloy's hardening posture turns three things off that a person debugging software expects to be on. Each has a way back; two of them are a command, and the third is a line in your image. ### dmesg says operation not permitted The kernel ring buffer takes a capability to read (`kernel.dmesg_restrict=1`). Two ways to the same text: run0 dmesg journalctl -k `journalctl -k` is the better habit: it is the same messages, it needs no privilege, and it survives a reboot. ### A program crashed and left no core file Alloy writes no cores. `kernel.core_pattern` is pointed at `/bin/false` and the hard limit is zero. A core is the process's memory written to disk, including whatever it had decrypted, which on this machine is keys and tokens. Getting one back takes root twice over, which is the intended friction: the pattern is a system setting, and the per-process hard limit is zero, so raising it needs `CAP_SYS_RESOURCE`. run0 sysctl -w kernel.core_pattern=core run0 bash -c 'ulimit -c unlimited; ./the-program-that-crashes' The core lands in the working directory, owned by root, and the program ran as root to produce it. Reboot when you are done, or set the pattern back by hand. `coredumpctl` is not the path here; `systemd-coredump` is not installed. ### modprobe refuses a module that exists A short list of filesystem drivers, legacy network protocols and the FireWire stack cannot be loaded at all, rather than merely being blocked from autoloading. The list and the reason for each entry are in `/usr/lib/modprobe.d/50-alloy-blacklist.conf`. If you need one back, delete its line from that file in your image checkout and rebuild. Editing it on the running machine does not last: `/usr/lib` is replaced on every update. Attaching a debugger is unaffected. `gdb -p` and `perf record -p` against your own processes still work; Alloy deliberately did not take the setting that would have stopped them. --- ## Reporting something Alloy is pre-v0 and this manual describes a moving system. If something here is wrong, the repository is at `makenot.work/git/max/alloy` and the design documents in `docs/` say what each piece is supposed to do, which is usually enough to tell a bug from a decision.