RBX docs Docs Idk

Fixing Errors

This 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

Alt text

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

error

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

a 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

ok

  • 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)

placeholder

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

placeholder 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}

placeholder

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

placeholder

and when we do a Google search we don’t get anything that relates to that

hi - hao

So what we can do here is maybe change the wording or adding roblox into the search to help Google search better

asaada

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

hi

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

a

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

ani (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.

joe