Fixing Errors
by:
haotian2006This section will go over some basics on how to fix or find errors
Checking Output
Usually, if your code doesn’t run then it might be because there was an error in your code. Which you can check by going to output.
To open output you go to View -> Output
TIP
Another useful tool is the Script Analysis, what it does is show warnings/errors (mainly syntax related) while you are editing the script. It is directly below the Output
To see if there is an error you will see a message that is red like this one
You can click on the error and it will bring you to the line and script that it errored on
If clicking on it doesn’t lead you anywhere and you see this
it means that the script it errored in was deleted. Which usually means it was a local script or a cloned script. What you can do is click on the error while in the game instead of after stopping and it should lead you to the right script.
Reading errors messages
- Time of message: When did it error
- Script Location: What script did it error on and where is the script
- Line the error is on: What line did it error on
- Error Message: What is the error
- Environment: is the error on the server, client, or studio
You mainly only need to focus on the Script Location, error line, and the error itself. If it’s an error you don’t understand you can use Google to search for the error message. There is a section below explaining how to do that.
???+ info “Common Error Messages” ### [name] is not a valid member of object This error shows up when you try to get a child that does not exist in the object, Usually if its to do with the client you can use WaitForChild but if that doesn’t work, check your code and make sure the child exists.
attempt to perform arithmetic(arithmetic) on number and [type]
This means you are trying to do arithmetic on a number and a type you can not do arithmetic on. The only objects you can do arithmetic on are numbers, strings, and objects that have arithmetic metamethods (**mul,**add…)
!!!info This also applies to attempt to compare something < number and attempt to concatenate string with something . They either must be types that be compared on concatenated or have the metatmethods that allow them to do it
Argument [number] missing or nil
This means that one of the arguments you sent is nil or empty. arguments are the data you are sending ex.
local function f(x) -- x is a parameter
...
end
f(y) -- y is an argument
to fix this make sure that the argument is being defined correctly or is the right type
Unable to cast value to Object
this means that the value you are trying to send cannot be converted into the object the function wants. To fix this make sure that the data type is the correct one.
Expected ’)’ (to close ’(’ at column [number]), got eof
This is a syntax error. it means that you either have extra parentheses or lack one. To fix this look for where the lines are underlined in red as roblox catches syntax errors before the game is being run.
Print Debugging
Print debugging mainly consists of adding print statements to find out what is wrong this is mainly used if no errors are showing up in the output
use case
let’s say we have a script set up like this
local x = getX()
local y = getY()
if x >= 3 then
if y == 0 then
doSomething()
end
end
and for some reason doSomething() is not being invoked, instead of going to scripting help and asking why the doSomething isn’t working here is what you can do.
1. Print before an if statement
local x = getX()
local y = getY()
print("script is running")
if x >= 3 then
print("x check passed")
if y == 0 then
print("y check passed")
doSomething()
end
end
When you run the script and you only see
script is running
x check passed
Then you will know that y is not equal to 0
!!! note You don’t really need to add all those prints to figure out what’s wrong for example if you know your code is running you can probably remove the print(“script is running”). You also can just print(“X”) (or anything that will help) instead of print(“x check passed”)
2. Printing the variables
local x = getX()
local y = getY()
print(x)
if x >= 3 then
print(y)
if y == 0 then
doSomething()
end
end
4
4
From this, you can tell that y is 4 not 0 so from this you would most likely look into how y is being assigned which in this case can tell us that something must be wrong with the getY function
visualize debugging
This type of debugging can be using parts or other methods to visualize the problem this can be used if using prints doesn’t really tell you what’s wrong
use case
Let’s say we are doing some raycasting but the ray isn’t hitting anything
local green = workspace.PartA
local red = workspace.PartB
local direction = (green.Position-red.Position).Unit*20
local ray = workspace:Raycast(green.Position,direction)
print(ray)
print(direction)
nil
600.8695068359375, -531.7534790039062, -596.8199462890625
For beginners, you might not see anything wrong with the script and looking at what direction is doesn’t really help, so what you can do here is create a part that goes in that ray direction like this
local green = workspace.PartA
local red = workspace.PartB
local direction = (green.Position-red.Position).Unit*20
local ray = workspace:Raycast(green.Position,direction)
print(ray)
local dir = Instance.new('Part')
dir.Size = Vector3.new(.2,.2,20)
dir.CFrame = CFrame.lookAt(green.Position+direction/2,green.Position + direction)
dir.Anchored = true
dir.Parent = workspace
From this we can see that direction is indeed wrong and when we look at how direction is defined we can see that we did (start-goal) when the proper way is (goal - start)
So fixing that and running the code will now give the correct results
local green = workspace.PartA
local red = workspace.PartB
local direction = (red.Position-green.Position).Unit*20
local ray = workspace:Raycast(green.Position,direction)
print(ray)
local dir = Instance.new('Part')
dir.Size = Vector3.new(.2,.2,20)
dir.CFrame = CFrame.lookAt(green.Position+direction/2,green.Position + direction)
dir.Anchored = true
dir.Parent = workspace
RaycastResult{PartB @ -4.82407379, 11.2030563, 18.3839722; normal = 0, 0, -1; material = Plastic}
Making your code more readable/ Remaking it
Sometimes making your code more readable will help with debugging ex: given this script it might be a bit annoying to figure out what wrong
--GOAL: to make the ProximityPrompt enabled set to true if both the flags for
-- randomTor and LocalTorso is false, otherwise true
if RandomTor:FindFirstChild("Flag").Value == false then
if LocalTorso:FindFirstChild("Flag").Value == false then
RandomTor:FindFirstChild("ProximityPrompt").Enabled = true
else
RandomTor:FindFirstChild("ProximityPrompt").Enabled = false
end
end
What we can do is use variables to make it cleaner
local randomFlag = RandomTor:FindFirstChild("Flag")
local LocalFlag = LocalTorso:FindFirstChild("Flag")
local RandomProx = RandomTor:FindFirstChild("ProximityPrompt")
if not randomFlag.Value then
if not LocalFlag.Value then
RandomProx.Enabled = true
else
RandomProx.Enabled = false
end
end
If you still don’t see what’s wrong with it what you can do is just plug values into it and think what the expected results are. The reason this isn’t working is because it ignores when randomFlag.Value is true so to fix this we can do:
local randomFlag = RandomTor:FindFirstChild("Flag")
local LocalFlag = LocalTorso:FindFirstChild("Flag")
local RandomProx = RandomTor:FindFirstChild("ProximityPrompt")
if (not randomFlag.Value) and (not LocalFlag.Value) then
RandomProx.Enabled = true
else
RandomProx.Enabled = false
end
!!!info
For people that really care how much lines their code has you can do
lua local randomFlag = RandomTor:FindFirstChild("Flag") local LocalFlag = LocalTorso:FindFirstChild("Flag") local RandomProx = RandomTor:FindFirstChild("ProximityPrompt") RandomProx.Enabled = not (randomFlag.Value or LocalFlag.Value)
as the condition is just a boolean
Using google
When you get an error message that you don’t know or understand, what you can do is go to google.com and search for the error message. Usually, you will find a devform post that has the same error and the solution. Another way to help enhance the search is by using "". This tells google to look for that keyword. Sometimes you might not get the results you’re looking for, for example, this error
and when we do a Google search we don’t get anything that relates to that
So what we can do here is maybe change the wording or adding roblox into the search to help Google search better
and there we go.
Using roblox debugger
Another way of debugging is using tools roblox provided such as breakpoints, watch, and call stack. But most of the time you won’t really be needing this. but if you want you can find out how to use them here.
Common mistakes
This section is just a list of common mistakes people tend to do
1. Using starter Gui instead of playergui
StarterGui
StarterGui is a container that is under Game. Its purpose is to act like a container to hold your guis before they are cloned into the PlayerGui. When a player joins roblox will take everything that is currently in StarterGui and clone them into the players PlayerGui. https://create.roblox.com/docs/reference/engine/classes/StarterGui
So given a script like the one below, it will not make ScreenGui visible because it is modifying a ScreenGui in StarterGui
--LocalScript
local StarterGui = game.StarterGui
local ScreenGui = StarterGui:WaitForChild("ScreenGui")
ScreenGui.Enabled = true --!! THIS WILL NOT WORK !!
PlayerGui
PlayerGui is a container that is under the player that joined. Each player will have their own PlayerGui which other players will not be able to see. The server will be able to see it but its is not recommended to let the server modify anything in PlayerGui. PlayerGui is what the client actually sees. https://create.roblox.com/docs/reference/engine/classes/PlayerGui
so to fix the given script above we can do this
--LocalScript
local player = game.Players
local LocalPlayer = player.LocalPlayer
local PlayerGui = LocalPlayer.PlayerGui
local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
ScreenGui.Enabled = true
2. LocalScripts in the wrong places
Another common mistake is having LocalScripts in the wrong place such as having a LocalScript in ServerScriptService. LocalScripts run in a client environment such as StarterPlayerScripts, ServerScriptService is on the server
https://create.roblox.com/docs/reference/engine/classes/LocalScript
3. Trying to access ServerStorage from the client
ServerStorage is a Storage for the server to see not the client. If you want to store something store it in ReplicatedStorage
4. Indirect Change
Indirect Change is when you are changing the variable, not the actual value, for example:
local t = {}
t.Value = 1
local value = t.Value
value = 5
print(t.Value) --> 1
print(value) -->5
--another example:
local part = workspace.Part
local position = part.Position
position = Vector3.new(1,2,3)
-- this is wrong
The example above is wrong because you are not changing the values but instead the variable.
the proper way to do this is to do:
local t = {}
t.Value = 1
t.Value = 5
print(t.Value) --> 5
--another example:
local part = workspace.Part
part.Position = Vector3.new(1,2,3)
5. Not having a BindToClose in their DataStoreSaving script
A very common mistake people tend to make is not having a BindToClose in their Datastore script
Here is an example script:
local dss =game:GetService("DataStoreService")
local MyDs = dss:GetDataStore("MyStore")
local function save(player)
MyDs:SetAsync(player.UserId,"your data")
end
game.Players.PlayerRemoving(save)
This will work, but will only work sometimes, this is because when the last person leaves roblox doesn’t care if a script is still running or not. To fix this you can use a BindToClose. What a BindToClose does is it forces roblox’s server or studio to wait until the function inside of it is done running (30 seconds max) then tell the server to close.
Heres is how we can implement it:
local dss =game:GetService("DataStoreService")
local MyDs = dss:GetDataStore("MyStore")
local function save(player)
MyDs:SetAsync(player.UserId,"your data")
end
game.Players.PlayerRemoving(save)
game:BindToClose(function()
for _,Player in game.Players:GetPlayers() do
save(Player)
end
end)
???+ warning Another mistake people tend to do is using spawn/task.spawn inside of the BindToClose
game:BindToClose(function()
for _,Player in game.Players:GetPlayers() do
task.spawn(save,Player)
end
end)
this is wrong because task.spawn makes it so that the saving process doesn’t yield, but we need it to yield. If you want to do it correctly you can do it like this
game:BindToClose(function()
local players = game.Players:GetPlayers()
local amt = #players -- how many players need to be saved
local count = 0 -- how many players have been saved
for _,Player in players do
task.spawn(function()
-- makes it so that everyone saves at the same time instead of 1 by 1
save(Player)
count += 1
-- when player is done saving increase
end)
end
repeat task.wait() until count == amt -- yields until everything is done
end)
or if you want to be fancy
game:BindToClose(function()
local players = game.Players:GetPlayers()
local thread = coroutine.running() --gets current thread
local amt = #players -- how many players needs to be saved
local count = 0 -- how many players has been saved
for _,Player in players do
task.spawn(function()
-- makes it so that everyone save at the same time instead of 1 by 1
save(Player)
count += 1
-- When player is done saving increase
if count == amt then
coroutine.resume(thread)
-- if it's the last player, resume the thread
end
end)
end
if count == amt then return end -- if everyone's data has already been saved there is no need to yield
coroutine.yield() -- yields the thread
end)
6. Animations working in Studio but not In game
Animations only work if the game the animation is owned is the same to fix it you will have to upload the animation to the same game owner or group
(The green is what will happen)
Conclusion
Hope this helps if you have any more questions you can ask in scripting-help. Anyways Good luck out there and don’t get joe tagged.