Guide to Debugging: Understanding Error MessagesA basic, and informative guide to understanding error messages.
Understanding error messages is an essential programming skill.
There are many scripters, that can script very well until they have an error, and they can’t manage to understand what went wrong.
#help-and-feedback:scripting-support is full of topics about simple errors, that with a basic understanding of the error messages, the issues can be solved quite easily.
In this guide, I will show you how to read and understand error messages efficiently.
What are error messages? How to see them?
Error messages, are the scripts’ way to let you know that something went wrong, usually can be seen in the output.
How to open the output:
Go to View(), and select Output().
After the script notices something was wrong, it’ll show you a red text (The error), or a yellow text (A warning) to let you know something was wrong.
How to read error messages? What do they mean?
In the error message, you’ll get: The error’s source, and a short description of the problem.
They mean something in that location, went wrong or couldn’t run for some reason.
Luckily, Roblox’s Lua error messages are pretty straight-forward and easy to understand:
Some other languages like Java have a much harder syntax:
Java Error Example compared to Roblox's Lua Error
This error is basically telling you that something is nil, so it throws an error to the output
Such an error in Roblox Lua can simply be viewed:
Attempt to index nil with ----, or Expected type1 got nil, and many others.
The Formula/Steps to approach an error message:
1. Identify the source of the error.
Error messages, almost always include the source of the error.
The source = Script Path, Line of the error, Server/Client, and sometimes column.
Here we have an error in the output, let’s find the source.
If we read it from left to right, the first thing we see is the path:
That means, that the script the error is referring to, is the script in ServerScriptService, and called MyMathScript.
Alright, so far so good, we have the location, but what’s next?
Now, we should identify where the script failed:
Right after the name, we get the main error’s line number:
That means, that in line 2, the script failed to run.
The line is also specified at the end of the main error line:
Multiple lines can show up in the stack trace
What is the "stack trace"?
A stack trace is a list of everything in the “chain reaction”.
What I mean by chain-reaction, is 1 thing, causing another thing, causing another thing, and so on.
For example, I used 2 functions, and 1 function call, the functions call each other causing a chain reaction.
Function test(name) call → function test(name) → function test3(name)
As you can see here, we first get the main source, the line where the script failed (Line 3 circled in red), that line is in function “test3”.
Then, we get the line that called function “test3” (Line 6, circled in blue), which is in function "test"
After that, we have the line that called function “test” in the first place (Line 8 circled in green).
It’ll go on from the operation itself to the rest of the things in the “chain reaction”.
Remember what we mentioned before? About locating the script in the error?
It applies in the stack trace too, not everything in the stack trace is necessarily within the same script. Different scripts and paths can occur here too.
Usually, if you click on the line in the stack trace, it’ll open the script editor in the correct place.
Here, the path is always ServerScriptService.MyMathScript.
A few extra things about the source
One more thing we can locate is whether the error was from the Client (Local Script), or from the server (Regular script).
Another thing to keep in mind, if you clone the script, it’ll let you know where it is now (at the moment it runs).
So if you get scripts in tools, GUIs and etc in such folders as “Backpack”, “PlayerGui”, “The Character”, “PlayerScript”. You should know that it is actually coming from the cloning folders: “StarterPack”, “StarterPlayerScript”, “StarterCharacterScripts”, “StarterGui” and etc.
2. Open the source
This step is pretty simple, after we identified the source, just go to it.
In my case, the script was:
--ServerScriptService.MyMathScript function test() --The last part of the chain reaction ---------------------------------------------------------- print(1 + nil) --The source of the error (Line 3) ---------------------------------------------------------- end function test() test3() --What was in the chain reaction end test() --What started the chain reaction
The stack trace showed me that the main error line is line 3 and that the other 6 and 8 are in the chain reaction.
3. Understand the error
Now after we found the problematic line:
print(1 + nil) --The source of the error (Line 3)
We still don’t know what to do, we just know where it failed.
Let’s return to the error message, we should find that after the source, we get a short and to-the-point description of the error:
Now, just read it. It is a pretty reader-friendly text".
Attempt - Tried to.
Arithmetic - Math.
Add - math addition, the + operator.
Get it? The script basically tells us: I tried to add nil (nothing) to a number.
Now let’s head back to our code line, we can see that we did actually do 1 + nil, which is something we can’t do.
So now we understand what happened and we can debug it.
Now, we understand what went wrong, and we understand where it went wrong.
The last thing to do is to make it right. Let’s replace nil with a number.
function test3() print(1 + 5) end function test() test3() end test()
As you can see, I replaced nil with 5. And now the code runs correctly, and we get , because 1 + 5 = 6.
The full process
Here I have another code part, and another error:
for i = 1,6,1 do Instance.new("Part", script.Parent)) end if(#script.Parent:GetChildren() == 7) print("I have 6 parts and 1 script") end
When we run the script, we get this first:
- First, we find the location: Which is line 2, in a Script called “PartSpawner”, which is in a folder called PartFolder, in the server.
- After we located the error: , we can find it in the script:
Instance.new("Part", script.Parent)) --Line 2
Alright, we found the source, let’s now understand the error:
Expected identifier - script expects something that isn’t there.
while parsing expression - while running the line.
Now let’s go back to the code and ask ourselves “what isn’t there that the script expects?”
Instance.new("Part", script.Parent)) --Line 2
- We can see there’s an extra “)”. This means, that the script was looking for the start of the bracket, and it found only the end.
So let’s remove it and try:
for i = 1,6,1 do Instance.new("Part", script.Parent) end if(#script.Parent:GetChildren() == 7) print("I have 6 parts and 1 script") end
Hooray! We fixed the issue! But we are not done yet, there’s another error (Part 2)
Let’s repeat the process again:
- Script is Located in PartFolder, called “PartSpawner”, and the main error is in line 5.
- Go to the source:
if(#script.Parent:GetChildren() == 7) --Line 5 print("I have 6 parts and 1 script") --Line 6
Now understand the message:
expected ‘then’ - The script expects the word “then” somewhere in this line.
when parsing if statement - When trying to run the if statement.
got ‘print’ - The script looks for ‘then’ after the if statement, but instead, it finds the print.
Now we understand that there should be a ‘then’ after the if, let’s fix:
for i = 1,6,1 do Instance.new("Part", script.Parent) end if(#script.Parent:GetChildren() == 7) then print("I have 6 parts and 1 script") end
Now let’s try to run it:
The script runs perfectly fine, we debugged it using the process “Locate, Understand, Debug”
-The print we ran.
You can do it with almost every error, but what about warnings?
Default Roblox warnings:
This time, we get the source in the stack trace:
Repeat the process once again:
- Script is located in MyFolder, the script is called “PartWaiter”, the error is in line 1
- Go to the source:
script.Parent:WaitForChild("MyTest") --Line 1, the source
- Now understand the error message:
infinite yield possible - Script on hold, the pause might not end.
We can understand, that the script can’t find “My Test”, so the script is waiting and waiting, and might even stay paused, because “MyTest” doesn’t exist.
Custom user warnings
Sometimes when writing code, you can do error handling with pcalls
For example, isn’t this code familiar?:
local data local success, err = pcall(function() data = DataStore:GetAsync("MyKey") end) if(success) then --Load data else warn(err) --Custom user warning end
In custom warnings, we don’t get a stack trace, but we do get the warning line:
Imagine this is an actually datastore script
So we repeat the process, although it’s a bit different:
- Locate the warning:
The user warning ran at line 8.
- Find it in the script:
This time it’s a little different because we get the warning line. But we can see that the warning came from our pcall, so we can assume that it is this line:
data = DataStore:GetAsync("MyKey")
warn(err) --Custom user warning
- Now let’s understand the warning:
Datastore API request was canceled because of an error.
Most of you know, that in security settings, API services are usually disabled on default:
It is pretty simple here, we just need to enable it:
The thing about User-Generated warnings is that the scripter decides what should be warned. In this case, the user decided they want to print out the datastore warning.
But what if I have a bug, and no error messages appear?
Then you should try to see which part of the code didn’t run, or didn’t run correctly.
The Lua Debugger and Prints are your best friend, Print in every section to see which print is ran:
local something = true local something2 = true local something3 = false --Imagine it's hard to find if(something) then print("First if ran") if(something2) then print("Second if ran") if(something3) then print("Third if ran") end end end
Here, for example, I want the third if statement to run, but it doesn’t run (imagine it was a long if statement and not just a print there) and there are no errors.
So I printed out in every section and found out that it isn’t reached:
Now, I want to find out why it doesn’t run, so I print my condition something3 and found out that it is false. If statements don’t run if the condition is false or nil.
The Lua Debugger:
The Lua debugger is a tool, that allows you to pause the script at certain parts, and see the information of the script.
You can also use the Lua Debugger to put breakpoints and see the variables’ values are. You’ll find out that something3 is false.
TL;DR/To sum up:
Roblox’s error messages are pretty straightforward, the error content is simple enough to understand.
The process of fixing is basically to:
- Locate the source of the error.
- Go to that source.
- Try to understand what the error message means.
- After you understand, go to the source (the code part) and fix it.
Sometimes, you’ll have bugs with no errors provided, so there are 2 main ways to find out what isn’t reached and didn’t work: The prints, and the Lua Debugger.
In the tutorial itself I provided much more detailed information, and examples than this TL;DR section
Hey developers , I hope this tutorial helped you.
Please let me know if I got anything wrong, or if there’s something I should add, or if you have any suggestions.
Have a great rest of the day/night!