Attempt to Index Field Parent (a nil value)

I’m back at it again with another error for my Harry Potter Wand! I finished Avada Kedavra, and I am working on the second spell, Crucio. For some reason, Crucio (which only has a different effect, everything else is the same) has a weird error. Avada Kedavra does not have this error. The error is 20:29:31.090 - ServerScriptService.Crucio:43: attempt to index field 'Parent' (a nil value).

Client:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local event = ReplicatedStorage:WaitForChild("Crucio")
local mouse = game.Players.LocalPlayer:GetMouse()
local player = game.Players.LocalPlayer
local orientation = script.Parent.Handle.Orientation
local SpellChatted = false
local VALID_DURATION = 4
local debounce = true

mouse.Button1Down:Connect(function()
	if debounce == true then
		debounce = false
		event:FireServer(mouse.Hit, orientation,SpellChatted)
		wait(4)
		debounce = true
	end
end)  

player.Chatted:Connect(function(msg)
	local msg = msg:lower()
	if msg:match("crucio") then
		SpellChatted = true
		print(player.Name.. "has typed in Crucio.")
		wait(VALID_DURATION)
		SpellChatted = false
	end
end)

Server:

local RepStorage = game:GetService("ReplicatedStorage")
local Event = RepStorage:WaitForChild("Crucio")
local wand = game.StarterPack.Wand

local function IsWandEquipped(character)
    for _, child in pairs(character:GetChildren()) do
        if child.Name == wand.Name then
          return true
        end
    end
    return false
end

local function avadakedavra(plr,hit, orientation,spellChatted)
    local character= plr.Character or plr.CharacterAdded:wait()
    if spellChatted and IsWandEquipped(character) then
		local ray = Ray.new(
			plr.Character.Head.CFrame.p,
			(hit.p - plr.Character.Head.CFrame.p).unit * 200)
		local ignore = plr.Character
		
		local part, position = workspace:FindPartOnRay(ray, plr.Character, false, true)
		local hit, position, normal = workspace:FindPartOnRay(ray, ignore)
		local beam = Instance.new("Part", workspace)
		beam.BrickColor = BrickColor.new("Really red")
		beam.FormFactor = "Custom"
		beam.Material = "Neon"
		beam.Transparency = 0.5
		beam.Anchored = true
		beam.Locked = true
		beam.CanCollide = false
		beam.Orientation = orientation
		beam.Shape = Enum.PartType.Block
		beam.Size = Vector3.new(1, 1, 1)
		local distance = (plr.Character.Head.CFrame.p - position).magnitude
		print(distance)
		beam.CFrame = CFrame.new(plr.Character.Head.CFrame.p - position)
		local start = plr.Character.Head.CFrame
		for i = 1, 500 do
			beam.CFrame = start:lerp(CFrame.new(position), i/10)
			wait()
		if part then
			local humanoid = part.Parent:FindFirstChild("Humanoid")
			
			if not humanoid then
				humanoid = part.Parent.Parent:FindFirstChild("Humanoid")
			end
			
			if humanoid then
				for i = 1, 10 do
					humanoid.Health = humanoid.Health - 9.5
				end
				beam:Destroy()
			end
			end
			wait()
		end
		wait(7)
		beam:Destroy()
    end
end

Event.OnServerEvent:Connect(avadakedavra)

The part does not seem to have a Parent from what the error message says.

1 Like

Yeah, that’s what’s confusing. It SHOULD have a parent.

Now I can’t see the spell, and it kills the player rather than giving him -95 damage.

It would have helped to have commented your code and pointed out where specifically your error was. It was fairly painful to count out your lines to find the source of error.

I feel that it’d be more worth your time to address all the potential or actual code problems that you’re having or that can be improved upon rather than going at the error specifically, since there’s a lot to be looked at in your code.

Client:

  • Try keeping your variables and constants together for better readability. You should also aim to use consistent conventions. Unless, well, you don’t care. Here’s what I typically use:

    • This in reference to all your variables being lowercase except for ReplicatedStorage, SpellChatted and VALID_DURATION.
  • Might be more helpful to send variables through remotes in the order that you check them in.

    • SpellChatted, orientation, mouse.Hit

    • First, you check if a spell was chatted. If it was, then you use the orientation of the Handle to determine a start point. Finally, you construct a Ray to mouse.Hit.

    • You may also want to consider not adding a debounce if a spell wasn’t chatted for the sake of UX design. Might hurt the experience to chant a spell but not be able to use it.

Server:

  • You broke convention using RepStorage over ReplicatedStorage! What happened!?

  • Everything from indexing the StarterPack’s Wand to the IsWandEquipped function is pointless overhead. Get rid of it. Keep the function but change how it works to something less intensive.1

  • For a receiving remote, don’t use CharacterAdded.Wait. Check if a character exists; if it doesn’t reject the request. Don’t stall the thread until the character exists.

  • MAIN SOURCE OF YOUR ERROR: Your code assumes that FindPartOnRay returns a non-nil part. When you use that method, it can return a nil value. Thus, when your code proceeds and doesn’t check if part is non-nil, it attempts to index Parent. Parent is not a valid member of nil.3

    • Even if the part does exist, Parent can be nil too. Parts with nil parents are typically not going to be in the Workspace or detectable, but just keep that in mind.
  • For some reason, you’re casting two rays? Get rid of the bottom one, you don’t use its arguments anyway and one them variable shadows a parameter sent to the function avadakedavra.2

  • Do NOT use the parent argument of Instance.new. Set your properties first and then set the Parent.4

    • A note that I’m just addressing your code work, but typically what I’d recommend here is that you pass this beam creation work to the client to render.

    • You can also get rid of unnecessary property setting.

[1]:

local function isWandEquipped(character)
    local tool = character:FindFirstChildWhichIsA("Tool")
    if tool and tool.Name == "Wand" then
        return true
    end
    return false
end

-- The function below is also acceptable:
local function isWandEquipped(character)
    local tool = character:FindFirstChildWhichIsA("Tool")
    return tool and tool.Name == "Wand"
end

[2]:

local part, position = workspace:FindPartOnRay(ray, plr.Character, false, true)

[3]:

if part and part.Parent then
    local humanoid = part.Parent:FindFirstChildWhichIsA("Humanoid")
    if not humanoid and part.Parent.Parent then
        humanoid = part.Parent.Parent:FindFirstChildWhichIsA("Humanoid")
    end
end

[4]:

-- It'd be better to create a function that makes and returns the beam.
local beam = Instance.new("Part")
beam.BrickColor = BrickColor.new("Really red")
beam.Material = Enum.Material.Neon
beam.Transparency = 0.5
beam.Anchored = true
beam.CanCollide = false
beam.Orientation = orientation
beam.Size = Vector3.new(1, 1, 1)
-- Got rid of distance calculation, you don't ever use distance
-- @ below, CFrame.p is deprecated in favour of CFrame.Position
beam.CFrame = CFrame.new(plr.Character.Head.CFrame.Position - position)
beam.Parent = workspace

Wow! Thanks for all of the information! There is one tiny issue. It still kills you when you cast crucio. It’s only supposed to take 95 damage, not 100.

If the damage is meant to be instantaneous (seeing as you do not include a wait in your loop), you can get rid of the loop and just subtract humanoid health, then remove the beam.

if humanoid then
    humanoid.Health = humanoid.Health - 95
end

Actually, in fact, your whole loop should be redone entirely. What’s happening here is that you have your loop, for i = 1, 500 right? The code in that loop runs 500 times. Your damage function is in that loop, so it runs 500 times on the detected humanoid.

Something you can do is create a variable in your code that determines if the humanoid was hit before. If they weren’t, damage them and set the variable to the humanoid. Next time the function checks to damage a humanoid, see if the humanoid is equal to that variable. If it is, do nothing, otherwise damage and set the variable.

In the long term though, restrict your for loop only to lerping the beam and keep the damage function outside of the loop.

1 Like

I never thought about the variable idea! Thanks!