What happened
A large idle.lock value in ~/.config/omarchy/shell.json overflows the idle service's QTimer interval, producing a runaway Qt warning loop that eventually exhausts shmem/tmpfs and takes the desktop down.
plugins/services/idle/Service.qml:267 binds the interval in milliseconds:
Timer {
id: lockTimer
interval: root.lockDelaySeconds * 1000
repeat: false
onTriggered: if (root.idleEnabled && root.idledThisCycle) root.lockSystem("lock-timeout")
}
QTimer/QQmlTimer intervals are a signed 32-bit int, so any lockDelaySeconds above 2147483 (~24.8 days) wraps negative. With idle.lock: 2592000 (30 days — a natural way to approximate "never lock"):
lockDelaySeconds = 2592000 - 150 = 2591850
2591850 * 1000 = 2591850000 ms
INT32_MAX = 2147483647
wraps to = -1702967296
Qt clamps the negative interval to 1ms and logs a warning on every timer start:
omarchy-shell[1194]: WARN: QBasicTimer::start: negative intervals aren't allowed; the interval will be set to 1ms.
Measured on my machine: ~424 warnings/second, 9,101,214 lines in a single session.
Impact
This is not just log noise. The flood escalates into a system-wide failure:
- Journald hits its 4G cap; weeks of real system history are rotated away.
- Quickshell's log memfd fills, and
shmem/tmpfs allocation starts failing:
omarchy-shell: ERROR quickshell.logging: Failed to copy log from memfd with error code 28 "No space left on device"
voxtype: WARN Failed to write PID file: No space left on device (os error 28)
uwsm_app-daemon: [Errno 28] No space left on device
wayland-wm-app-daemon.service crashes on the ENOSPC and enters a restart loop. Each restarted daemon receives a truncated request:
uwsm_app-daemon: received:
uwsm_app-daemon: sent: error 'Invalid arguments: ' 2
- Every app launch then fails with a critical
App failure / Invalid arguments: desktop notification (urgency: 2, expireTimeout: 0, so they never expire and persist across restarts).
The machine became unusable and needed a hard restart. Note that df shows plenty of free disk throughout — the ENOSPC is shmem exhaustion, which makes this quite hard to diagnose from the symptom.
Steps to reproduce
- Set in
~/.config/omarchy/shell.json:
"idle": { "screensaver": 150, "lock": 2592000 }
- Leave the machine idle for 150s so the idle cycle starts and
lockTimer arms.
- Watch the flood:
journalctl -f | grep QBasicTimer
omarchy-shell idle status # "lockDelay": 2591850, "timers": { "lock": true }
Expected
Either the timer is armed correctly for the configured duration, or the value is clamped/rejected — not silently wrapped into a 1ms busy loop.
Suggested fix
secondsFromConfig in plugins/services/idle/IdleModel.js already guards the low end but not the high end:
function secondsFromConfig(value, fallback) {
var n = Number(value)
if (!isFinite(n) || n < 0) return fallback
return Math.floor(n)
}
Clamping to the largest value that survives the * 1000 conversion would fix it:
// Timer intervals are milliseconds in a signed 32-bit int.
var MAX_TIMER_SECONDS = 2147483 // floor(INT32_MAX / 1000)
function secondsFromConfig(value, fallback) {
var n = Number(value)
if (!isFinite(n) || n < 0) return fallback
return Math.min(Math.floor(n), MAX_TIMER_SECONDS)
}
screensaverDelaySeconds (Service.qml:260) has the same exposure and would be covered by the same clamp.
Separately, it may be worth giving idle.lock an explicit "never" sentinel (e.g. 0 or false), since approximating it with a large number is what leads users into this.
System details
|
|
| Omarchy |
4.0.2-1 |
| Kernel |
7.1.9-arch1-2 |
| CPU |
Intel Core i5-10400F |
| GPU |
NVIDIA GeForce GTX 1660 Ti (TU116) |
| quickshell |
0.3.1-1 |
| qt6-base |
6.11.2-2 |
Related
What happened
A large
idle.lockvalue in~/.config/omarchy/shell.jsonoverflows the idle service's QTimer interval, producing a runaway Qt warning loop that eventually exhausts shmem/tmpfs and takes the desktop down.plugins/services/idle/Service.qml:267binds the interval in milliseconds:QTimer/QQmlTimerintervals are a signed 32-bit int, so anylockDelaySecondsabove2147483(~24.8 days) wraps negative. Withidle.lock: 2592000(30 days — a natural way to approximate "never lock"):Qt clamps the negative interval to 1ms and logs a warning on every timer start:
Measured on my machine: ~424 warnings/second,
9,101,214lines in a single session.Impact
This is not just log noise. The flood escalates into a system-wide failure:
shmem/tmpfs allocation starts failing:wayland-wm-app-daemon.servicecrashes on the ENOSPC and enters a restart loop. Each restarted daemon receives a truncated request:App failure / Invalid arguments:desktop notification (urgency: 2,expireTimeout: 0, so they never expire and persist across restarts).The machine became unusable and needed a hard restart. Note that
dfshows plenty of free disk throughout — the ENOSPC is shmem exhaustion, which makes this quite hard to diagnose from the symptom.Steps to reproduce
~/.config/omarchy/shell.json:lockTimerarms.Expected
Either the timer is armed correctly for the configured duration, or the value is clamped/rejected — not silently wrapped into a 1ms busy loop.
Suggested fix
secondsFromConfiginplugins/services/idle/IdleModel.jsalready guards the low end but not the high end:Clamping to the largest value that survives the
* 1000conversion would fix it:screensaverDelaySeconds(Service.qml:260) has the same exposure and would be covered by the same clamp.Separately, it may be worth giving
idle.lockan explicit "never" sentinel (e.g.0orfalse), since approximating it with a large number is what leads users into this.System details
Related
App failuretoasts pile up and survive restarts; this bug is one way to generate them in bulk.idle.screensaver/idle.lockhandling inshell.json.