Debugging
A plugin that fails never takes Nari down with it. When a script raises an error, Nari shows a message at the bottom
of the screen with the plugin’s name, what went wrong and where (main.lua, line 12), logs it with its stack trace,
and keeps going. That covers:
- syntax errors, in
main.lua, in modules loaded withrequireand in thread scripts - runtime errors: reading a field of
nil, calling something that doesn’t exist, math on text,error(...), a stack overflow - Godot calls that fail: a missing method, wrong arguments, a freed object, a property that doesn’t exist or gets a value of the wrong type
- missing files: a
required module, anari.threadscript, a manifest’smain, a brokenmanifest.json - errors inside event handlers, timers, signal handlers, settings actions, visualizers and threads
Most errors only skip the code that failed and the plugin stays on. The same error shown again only bumps a counter on its message.
When Nari stops a plugin
Section titled “When Nari stops a plugin”main.luafails while it starts- the main thread runs plugin code for more than 3 seconds without returning, like an endless loop
- a Lua state goes over 128 MB of memory
- it fails 20 times within 5 seconds, like an error every frame
A stopped plugin stays off until Nari restarts, the plugin is turned off and on, or F5 is pressed in developer
mode. Errors are also in Plugins.errors (newest last, with id, name, message, file, line, trace,
fatal and time), and Plugins.plugin_failed fires for each one.
Developer mode
Section titled “Developer mode”Settings → General → Developer mode turns on these keys:
| Key | |
|---|---|
| F12 | A console over the app with every log since Nari started, plugin errors and their stack traces included. It filters by text and level, copies what it shows and runs GDScript expressions, like MediaPlayer.get_current_song(). Esc closes it. |
| F5 | Reloads every plugin from disk, including stopped ones, and leaves safe mode. |
| F6 | Reloads the current screen, to see what your plugin changes when a screen opens. |
| F3 | Shows FPS, frame time, memory, nodes and draw calls. |
| Alt+R | Restarts Nari. |
The same actions are entries in Settings → General, for devices without a keyboard. With developer mode on, tapping an error message opens the console.
Console commands
Section titled “Console commands”The console takes commands: ↑ and ↓ go through the ones you typed, Tab completes a name, help lists
them all and help <command> explains one.
| Command | |
|---|---|
play [song id | words] |
Resumes, plays a song by id, or plays the best match of a search. |
pause, toggle, next, prev |
Playback. |
seek <1:23 | 83 | +10 | -10> |
Jumps to a time or moves by seconds. |
now, queue |
The current song (with ids, position, shuffle, repeat and effect) and the queue. |
search <words> |
Songs, albums and artists with their ids. Quotes keep words together: play "the song". |
shuffle [on | off], repeat [off | all | one], effect [name | off] |
Playback modes. effect alone lists every effect. |
open <screen> [id], back |
Opens home, tracks, album <id>, settings <category>, nowplaying… |
library |
The music provider and how many songs, albums and artists it has. |
plugins, plugin <on | off> <id>, reload [page], errors [count] |
Plugin state, turning them on and off, reloading, and the latest errors. |
get <section.key>, set <section.key> <value> |
Reads or changes a setting, like set general.developer_mode false. |
stats, clear, restart |
Same as F3, clearing the console, Alt+R. |
Anything that isn’t a command runs as a GDScript expression.
Your own commands
Section titled “Your own commands”nari.command("lyrics_cache", "Shows or clears the cached lyrics", function(args) if args[1] == "clear" then nari.set("cache", nil) return "Cleared" end local lines = {} for title in pairs(nari.get("cache") or {}) do table.insert(lines, title) end return linesend)args is the list of words after the name (quoted text counts as one). Return a string, a list of lines or nothing.
Names can’t have spaces or repeat an existing command, and the command goes away when the plugin turns off.