Debugging & Logging
How to find and fix problems in your scripts: reading logs and errors, reloading your code quickly and inspecting your UIs.
Printing to the Console
The Console Static Class outputs messages to the console (and to the log files), with different levels:
Console.Log("Normal message") -- always shown
Console.Warn("Something looks wrong") -- orange, shows the stack trace
Console.Error("Something is broken") -- red, shows the stack trace
Console.Debug("Only shown with log level 2 or 3") -- hidden by default
All of them support formatting with string.format specifiers, so you don't need to concatenate values yourself:
Console.Log("Player %s has %d health at %s", player:GetName(), character:GetHealth(), tostring(character:GetLocation()))
print(...) also works, it's redirected to Console.Log.
To print the contents of a table, use NanosTable.Dump(my_table).
Log Levels
By default Console.Debug messages and internal verbose logs are hidden. To see them:
- Server: set
log_level = 2(debug) or3(verbose) in the[debug]section of the Config.toml, pass--log_level 2when starting the server, or run the console commandlog_level 2. - Client: change the log level in the game settings, under the Debug section.
Where are the Logs?
Everything printed to the console is also saved to disk:
| Side | Location |
|---|---|
| Server | .logs/ folder next to the server executable. NanosWorldCore.log is the latest session, older sessions are kept with their date in the file name |
| Client | %LocalAppData%\NanosWorld\Saved\Logs\ |
On the client, you can also open the in-game Console with its key binding (configurable in the settings) to see the logs and run commands while playing.
Reading Lua Errors
When a script fails, the error is printed in red with where it happened (e.g. inside which Event), followed by the stack trace: the chain of function calls which led to the error, with the file and line of each one. The first line ([1]) is where the error happened. For example:
ERROR Lua Error on Class 'my-package' Event 'TakeDamage':
- [1] [my-package/Server/Index.lua]:24: attempt to call a nil value (global 'Sound')
- [2] [my-package/Server/Index.lua]:77: in function <[string "my-package/Server/Index.lua"]:69>
This means that in the line 24 of my-package/Server/Index.lua, inside a TakeDamage event, the code tried to call Sound(...), but Sound doesn't exist there. In this case because Sound is a client-only class and the code is running on the server!
Always fix the first error you see. Other errors that follow are usually consequences of it.
Common errors and what they usually mean
attempt to index a nil value
A function returned
niland you used the result, e.g.player:GetControlledCharacter()when the Player isn't possessing anything, orProp.GetByIndex(10)when there are fewer Props. Check fornilbefore using it
attempt to call a nil value (method 'X') or (global 'X')
The method or class doesn't exist, or it's not available on that side (e.g. spawning a client-only class on the server). Check the name and the Authority of it in the Scripting Reference
attempt to concatenate a boolean/nil value
Using
..with something which is not a string or number. Usetostring(value)or theConsole.Log("%s", value)formatting
attempt to perform arithmetic on a nil value
A variable you are doing math with was never set, e.g. a
GetValuewhich returnednil. Pass a fallback:GetValue("score", 0)
Expected a class as parameter
You passed a string to
IsA, use the class itself:entity:IsA(Weapon)
Invalid Channel!, Invalid Index!, etc
A parameter is outside its allowed range, check the method description in the Scripting Reference
Reloading your Code
You don't need to restart the server to test your changes. In the server console, use:
package reload my-package
Unloads and loads the Package again, destroying the entities it spawned (if
auto_cleanupis enabled). Players receive the updated client files automatically
package hotreload my-package
Reloads all files but keeps the Lua memory (global variables) as is |
package reload all
Reloads all Packages, restarting the whole Lua Virtual Machine |
Since the Load event is triggered again when reloading, it's a good practice to write your Package so it works when reloaded while Players are already connected. For example, when spawning Characters for Players on Player "Spawn", also loop through the already connected Players on Package "Load" (see the Quick Start).
Debugging WebUIs
WebUIs run a real Chromium browser, so you can use its Developer Tools to inspect the HTML, see JavaScript errors and debug your code:
local my_ui = WebUI("My UI", "file://UI/index.html")
-- Opens the Chromium DevTools for this WebUI
my_ui:OpenDevTools()
JavaScript console.log messages are also shown in the game console, with the WebUI log type.
Debugging the World
- The Debug Static Class draws lines, boxes, spheres and texts in the world, which is great to visualize locations, directions and traces. Traces can also draw themselves with
TraceMode.DrawDebug. - To see how entities are synchronized and who is their Network Authority, enable Draw Network Debug in the settings (Settings -> Debug). See Debugging Network & Network Authority.
-- Draws a red sphere for 10 seconds where a Character is
Debug.DrawSphere(my_character:GetLocation(), 50, 12, Color.RED, 10)
Performance Issues
If your server logs Server Tick too high! warnings or the game gets slow, check the Profiling guide to find which code is taking too long.