Guide to Debugging: Understanding Error Messages

Guide to Debugging: Understanding Error Messages

A basic, and informative guide to understanding error messages.

Introduction:

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.

The Guide:

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(image), and select Output(image).

You should now see a window that looks like this

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.

Examples:

image
image
image

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

image
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.
image
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:image
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:
image
That means, that in line 2, the script failed to run.
The line is also specified at the end of the main error line:image

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)
image
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:
image

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.

4. Debugging

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 image , because 1 + 5 = 6.

The full process
Part 1:

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:
image

  1. First, we find the location: Which is line 2, in a Script called “PartSpawner”, which is in a folder called PartFolder, in the server.
  2. After we located the error: image , we can find it in the script:
	Instance.new("Part", script.Parent)) --Line 2
  1. Alright, we found the source, let’s now understand the error:
    image
    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
  1. 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)

Part 2:

image
Let’s repeat the process again:

  1. Script is Located in PartFolder, called “PartSpawner”, and the main error is in line 5. image
  2. Go to the source:
if(#script.Parent:GetChildren() == 7) --Line 5
	print("I have 6 parts and 1 script") --Line 6
  1. Now understand the message:
    image
    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.

  2. Debug
    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”
image -The print we ran.

You can do it with almost every error, but what about warnings?

Default Roblox warnings:

Such as:
image
This time, we get the source in the stack trace:
image
Repeat the process once again:

  1. Script is located in MyFolder, the script is called “PartWaiter”, the error is in line 1
  2. Go to the source:
script.Parent:WaitForChild("MyTest") --Line 1, the source
  1. Now understand the error message:
    infinite yield possible - Script on hold, the pause might not end.
    On :WaitForChild().
    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:
image

Imagine this is an actually datastore script

So we repeat the process, although it’s a bit different:

  1. Locate the warning:
    image
    The user warning ran at line 8.
  2. 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")
	And not:
	warn(err) --Custom user warning
  1. Now let’s understand the warning:
    image
    Datastore API request was canceled because of an error.
    Most of you know, that in security settings, API services are usually disabled on default:
    image
  2. Debug:
    It is pretty simple here, we just need to enable it:
    image

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:

Prints:
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:
image
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:

  1. Locate the source of the error.
  2. Go to that source.
  3. Try to understand what the error message means.
  4. 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 :slightly_smiling_face:, 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!
@LightningLion58

16 Likes