Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

FAQ

Symptoms whose cause lives on another page: find the symptom, then follow the link. A trap that stays within one page is in that page’s Gotchas table.

First steps when something is wrong

StepCommandTells you
1mantle checkSyntax and top-level errors, with file and line. Node and layout errors as laid out with every capability nil, then with sample data (what check covers)
2mantle logEvaluation errors, layout errors, errors raised in callbacks, failed mantle calls and refused mantle set/toggle writes (output and logging)
3MANTLE_DUMP_LAYOUT=<id>@<output> mantle -vvvEvery visible node’s kind and rect on that surface after each pass (how do I)

Nothing shows

SymptomCauseFix
No surface appears at all after startingThe startup evaluation raised, so there is no scene. The error is in the logEvaluation, reload and generations
mantle check passes, but a surface is empty or lays out wrongcheck lays out on a 1920x1080 output with every capability nil, then with one sample value each, so a branch that needs a particular value, or a smaller output, went unchecked. The running shell reports those in mantle logWhat check covers, then the layout dump and the layout model
A node shows before its data arrivesThe map returns nil for visible, which counts as absent, and visible defaults to truesignals gotchas
Two bars on screenTwo shells are running, one per mantle startmantle list, then mantle stop --pid <pid> (shell selection)
The shell vanishes and comes back only after 30 sThe Renderer died three times within 60 s, so the next respawn waitsFix the error in mantle log (limits)

A save or a click does nothing

SymptomCauseFix
Saving a file leaves the old UI on screen, and mantle.rescue.is_rescue is trueThe reload failed: an evaluation or apply error keeps the previous scene, sets mantle.rescue and logs the error. The next reload that applies clears itFind out why a reload did nothing, error banner
After a broken save, mantle call says the action does not exist, timers stop and on_change goes quietThe save raised a Lua error: a failed evaluation drops every action, timer, handler and idle threshold. A save that evaluates but fails to apply keeps its actions and handlers, not its timersEvaluation, reload and generations
An on_change, timer, process.run, palette or idle callback does nothingIts error is a warning, and so is a blown CPU budget in on_change or timer. Read mantle logOutput and logging
mantle.<cap>:<action>(...) returns nil and nothing changesActions are fire and forget. A wrong argument raises at the call, so the Supervisor refused what needs its live state, such as a stale ID, with a log lineRead mantle log; actions
A keybind running mantle set or mantle toggle does nothingIt may have been refused (an undeclared name, a bare toggle on a non-boolean). The compositor discards the errorRun the command in a terminal or read mantle log (values and arguments)
Saving a .json or an image beside shell.lua does not reloadOnly .lua and .frag changes reload; a byte-identical save and an unreadable directory (changes inside it will not reload) do not eitherEvaluation, reload and generations
An edit to fonts { ... } does nothingThe font chain is read when the Renderer startsRestart the shell (fonts)
A textfield shows no caret and takes no keysThe panel does not take keyboard focustext fields, panel

Values are wrong or stale

SymptomCauseFix
A :get() raises attempt to index a nil value at startup, or a capability reads nilEvery capability reads nil until its first push, for mantle check’s first pass, and for good when its backend is missing (lock and polkit push at startup, so they read nil only while a relock is pending); :map and computed skip the nilThe one rule, capabilities
A text never updatesIt holds a :get() snapshot, not the signalThe one rule
A setting is lost after the shell restartsNamed state lives in the Renderer and dies with itpersistent_table
A switched view keeps old state, or snaps in without its animationvisible = false freezes the subtree in place; two id-less views of the same kind are reusedSwitching views, nodes

Errors in the log

MessageCauseFix
surface 2 is a string, not a noderequire returned the module and its path into the surface listModules and require
exceeded the 50ms CPU limit for one evaluationA map, computed, handler or timer ran away or did far too much workLimits and budgets
signal nesting exceeded its maximum depth of 32 levelsA derived chain reads itself or nests too deepErrors
a Signal resolved to another SignalA map returned a signalErrors
`margin.left` is a Signal handleA signal inside a table a signal returned, or under a metatable, is not readsignals gotchas
`mantle` asked to write state ... and was refusedmantle set/toggle named an undeclared state, or wrote a value it refusesValues and arguments

Running processes

SymptomCauseFix
process.run prints nothing and on_exit gets nilThe spawn failed, usually a command not on PATH. mantle log has the reasonprocess.run
A program runs twice after a saveA top-level process.detach launches again on every reloadsession_process, What survives a reload

Capabilities

A capability starts on the config’s first mantle.<name> read, so a config that never reads it runs no server, watcher or agent. The quoted log lines need -v or -vv.

SymptomCauseFix
A capability reads nil or stays inertIts backend is missing or started after the shell (requirements); sysinfo and updates wait for configure; or the config reads mantle.<name> only inside a callback that never ranStart the backend, then restart the shell: a reload does not retry. Call configure where the page says so. Read mantle.<name> at config top level
battery.present is falseUPower’s display device is not a present battery (desktop, or battery not detected), or UPower is not running (state "unknown")Expected on desktops; otherwise start upower.service; upower -d should list DisplayDevice
No tray iconsConfig never reads mantle.tray; another host (waybar, snixembed) owns org.kde.StatusNotifierWatcher; the app is XEmbed-only; or it registered at an unlisted path before the shell startedRead mantle.tray; stop the other host; restart an SNI app so it registers again. An XEmbed-only app cannot show
Notifications not showingAnother daemon (mako, dunst, swaync) owns org.freedesktop.Notifications (another notification daemon already owns this name), or the config never reads mantle.notificationsStop and disable the other daemon, then restart the shell. busctl --user status org.freedesktop.Notifications names the owner
No notification soundDND or quiet on (critical still plays); the app is muted; the file is not Ogg Vorbis or 16-bit WAV, is over 4 MiB or 30 s, or lies outside the sound roots; sound-name with no tier sound registerednotifications backend
Polkit prompts not appearingConfig never reads mantle.polkit, so the agent never registers; another agent (polkit-gnome, hyprpolkitagent) registered first; $XDG_SESSION_ID unsetRead mantle.polkit; stop the other agent and restart the shell; start the session through logind
Polkit authentication always fails/run/polkit/agent-helper.socket is missing, so the helper cannot runCheck that the installed polkit provides that socket
Idle never firesA block-mode idle inhibitor is held (systemd-inhibit --list), a browser or player holds ScreenSaver, a Wayland surface inhibitor is up, or the config’s own inhibit is still held; or the compositor lacks ext_idle_notifier_v1mantle.idle.inhibited and inhibitors name the holder (empty who is the compositor)
Unlock refuses the right passwordPAM stack login in use and pam_nologin or pam_shells refusingInstall the mantle PAM stack (install)
Locked session with no lock screenThe Renderer died and its replacement could not retake the lock (could not take the session lock over)Switch VT and unlock through the compositor’s own mechanism
Keyboard layout switch does nothingNo supported compositor, only one layout configured (layout_count 1), or the compositor refused the switchConfigure several layouts in the compositor; on Hyprland, MANTLE_LOG=debug shows the reply to switchxkblayout main <i>
Caps/Num Lock always falseNo readable /dev/input keyboard with LEDs and no sysfs LEDGive the user read access to the input device
brightness reads nilNo /sys/class/backlight device; external monitors are not coveredNone; brightness is backlight-only
Brightness writes ignoredSession not active (another VT), so logind refuses SetBrightnessSwitch back to the session
Pairing prompt never showsThe adapter is not visible and this shell did not start the pairingMake the adapter visible or pair from the shell; PIN and passkey entry use a secure field

See also: runtime, cli, signals, processes, capabilities, glossary (rescue, hydration, generation).

Source: reload and rescue, apply, check, callback logging, log subsystems.