Attempt to index nil with 'FindFirstChild' on minigame script

I got the error: ServerScriptService.Main:100: attempt to index nil with ‘FindFirstChild’ - Server - Main:100

does anyone know what went wrong?

script:

	gameRunning = false,
	playersAlive = {},
	currentMap = nil
}

local waitForChild = game.WaitForChild
local findFirstChild = game.FindFirstChild



local settingsModule = require(waitForChild(script, "Settings"))
local onWin = (function()
	local onWinModule = findFirstChild(script, "OnWin")
	
	if onWinModule then
		local onWinFunction = require(onWinModule)
		
		if type(onWinFunction) == "function" then
			return onWinFunction
		end
	end
end)()

local remoteEvent = waitForChild(game:GetService("ReplicatedStorage"), "Event")
local mapsStorage = waitForChild(game:GetService("ServerStorage"), "Maps"):GetChildren()

local playersService = game:GetService("Players")

function minigameModule.isPotentialGame()
	return playersService.NumPlayers >= settingsModule.minimumPlayers
end

function minigameModule:chooseMap()
    local chosenMap = mapsStorage[math.random(#mapsStorage)]:Clone() 
	if findFirstChild(chosenMap, "Spawns") then
		chosenMap.Parent = workspace
		chosenMap:MakeJoints()
		self.currentMap = chosenMap
		return chosenMap
	end
end

function minigameModule:spawnPlayers()
	local playersAlive = self.playersAlive
	local spawns = self.currentMap.Spawns:GetChildren()
	for index = 1, #playersAlive do
		local playerData = playersAlive[index]
		playerData.playerHumanoidRoot.CFrame = spawns[math.random(#spawns)].CFrame
	end
end

function minigameModule:runIntermission()
	if settingsModule.intermissionTime > 0 then
		for currentTime = math.floor(settingsModule.intermissionTime), 0, -1 do
			remoteEvent:FireAllClients("Timer", currentTime)
			wait(1)
		end
	end
	remoteEvent:FireAllClients("CeaseGUIs")
end

function minigameModule:getAlivePlayers()
	local playersAlive = {}
	for index, currentPlayer in next, playersService:GetPlayers() do
		local playerCharacter = currentPlayer.Character
		if playerCharacter then
			local playerHumanoidRoot = findFirstChild(playerCharacter, "HumanoidRootPart")
			local playerHumanoid = findFirstChild(playerCharacter, "Humanoid")
			if playerHumanoid and playerHumanoidRoot then
				table.insert(playersAlive, {
					player = currentPlayer,
					playerHumanoid = playerHumanoid,
					playerHumanoidRoot = playerHumanoidRoot
				})
			end
		end
	end
	return playersAlive
end

function minigameModule:isLegalGame()
	if #self:getAlivePlayers() >= settingsModule.minimumPlayers then
		return true
	end
end

function minigameModule:queryGameStart()
	if self.gameRunning then
		return
	elseif self.isPotentialGame() then
		self.gameRunning = true
		remoteEvent:FireAllClients("CeaseGUIs")
		self:runIntermission()
		
		if self:isLegalGame() then
			if settingsModule.roundDuration > 0 then
				
				local currentMap = self:chooseMap()
				local mapWeapons = currentMap:FindFirstChild("Weapons")
				
				local playersAlive = self:getAlivePlayers()
				self.playersAlive = playersAlive
				
				for index = 1, #playersAlive do
					local currentPlayer = playersAlive[index]
					local backpack = findFirstChild(currentPlayer.player, "Backpack")
					
					if backpack and mapWeapons then
						for index, weapon in next, mapWeapons:GetChildren() do
							weapon:Clone().Parent = backpack
						end
					end
					
					local connection
					connection = currentPlayer.playerHumanoid.Died:connect(function()
						connection:disconnect()
						table.remove(playersAlive, index)
						if #playersAlive < 2 then
							local winner = playersAlive[1]
							if winner then
								self:endGame(winner.player.Name .. " has won!", winner.player)
							else
								self:endGame("No one has won!")
							end
						end
					end)
				end
				
				if mapWeapons then
					mapWeapons:Destroy()
				end
				
				self:spawnPlayers()		
				
				remoteEvent:FireAllClients("Message", currentMap.Name .. " was chosen!", 5)
				
				for currentTime = settingsModule.roundDuration, 0, -1 do
					if not self.gameRunning then
						return
					end
					remoteEvent:FireAllClients("Timer", currentTime)
					wait(1)
				end
				self:endGame("The timer ran out! No one has won!")
			end
			
		else
			self:endGame("Not enough players alive to begin the round!")
		end
	else
		local remainingPlayers = settingsModule.minimumPlayers - playersService.NumPlayers
		remoteEvent:FireAllClients("Message", "Waiting for " .. remainingPlayers .. " player" .. (remainingPlayers > 1 and "s" or "") .. " to join.")
	end
end

function minigameModule:endGame(outputMessage, winner)
	if self.gameRunning then
		
		self.gameRunning = false
		self.currentMap:Destroy()
		self.currentMap = nil
		
		if winner and onWin then
			onWin(winner)
		end
		
		for index, player in next, playersService:GetPlayers() do
			player:LoadCharacter()
		end
		
		wait(1)
		
		remoteEvent:FireAllClients("Message", outputMessage, 5)
		
		wait(5)
		
		self:queryGameStart()
	end
end

function minigameModule:removePlayer(player)
	if self.gameRunning then
		for index = 1, #self.playersAlive do
			if self.playersAlive[index].player == player then
				table.remove(self.playersAlive, index)
				if #self.playersAlive <= 1 then
					self:endGame("Not enough players to continue the game.")
				end
				break
			end
		end	
	end
end

playersService.PlayerAdded:connect(function()
	minigameModule:queryGameStart()
end)

playersService.PlayerRemoving:connect(function(player)
	minigameModule:removePlayer(player)
end)

When it says nil, it means that the object doesn’t exist, and you’re attempting to index it with :FindFirstChild() or anything else.

So it has to do with the variable that’s nil.

1 Like

what is this?? what are you trying to do?

1 Like

I was trying to make it easier to reference them, is that what’s causing the problem?

yes ?? youre literlaly looking for instances inside game datamodel

2 Likes

So how would I go about fixing this, I removed the two things at the top and replaced all the instances that needed it.

does it still error with indexing nil

yes, I don’t know what could be going wrong.

Aha, found the problem.

This code, in math.random, it has minimum value, but doesn’t have maximum value.

local chosenMap = mapsStorage[math.random(#mapsStorage)]:Clone() 

I supposed you intended it to be like this:

local chosenMap = mapsStorage[math.random(1, #mapsStorage)]:Clone() 

The change did, oddly enough, make the gui timer work again, but the error is still present.

I’ve modified this a bit, does it work for you?

function minigameModule:chooseMap()
	local chosenMap = mapsStorage[math.random(1, #mapsStorage)]:Clone() 
	if chosenMap:FindFirstChild("Spawn") then
		chosenMap.Parent = workspace
		chosenMap:MakeJoints()
		self.currentMap = chosenMap
		return chosenMap
	end
end

So the findFirstChild error is gone, but now I have the error: MakeJoints is not a valid member of Folder “Workspace.Sword Fight!”

Well I just found out that MakeJoints() is now deprecated, same for BreakJoints()

So feel free to remove chosenMap:MakeJoints(), but if your map needs some welding, you can install a plugin called NAAP Tools, which has many options including welding parts that are close together automatically.

So rid of the make joints error, but the original error is somehow back for the same line.

ServerScriptService.Main:97: attempt to index nil with ‘findFirstChild’

I’ve modified it.

function minigameModule:getAlivePlayers()
	local playersAlive = {}
	for _, currentPlayer in pairs(playersService:GetPlayers()) do
		local playerCharacter = currentPlayer.Character
		if playerCharacter then
			local playerHumanoidRoot = playerCharacter:FindFirstChild("HumanoidRootPart")
			local playerHumanoid = playerCharacter:FindFirstChild("Humanoid")
			if playerHumanoid and playerHumanoidRoot then
				table.insert(playersAlive, {
					player = currentPlayer,
					playerHumanoid = playerHumanoid,
					playerHumanoidRoot = playerHumanoidRoot
				})
			end
		end
	end
	return playersAlive
end

I’ve seen many developers add a variable to the index in for loops despite not using it, so please, add an underscore to it if you’re not using it.

The underscore (_) variable name is a convention in lua that indicates an unused variable.

This prevents memory leaks.

I’m sorry to say this, but the error is still persisting, ServerScriptService.Main:97: attempt to index nil with ‘findFirstChild’

I’ve modified the entire code you showed.

local minigameModule = nil

local settingsModule = require(script:FindFirstChild("Settings"))
local onWin = (function()
	local onWinModule = script:FindFirstChild("OnWin")

	if onWinModule then
		local onWinFunction = require(onWinModule)

		if type(onWinFunction) == "function" then
			return onWinFunction
		end
	end
end)()

local remoteEvent = game:GetService("ReplicatedStorage").Event
local mapsStorage = game:GetService("ServerStorage").Maps:GetChildren()

local playersService = game:GetService("Players")

function minigameModule.isPotentialGame()
	return playersService.NumPlayers >= settingsModule.minimumPlayers
end

function minigameModule:chooseMap()
	local chosenMap = mapsStorage[math.random(1, #mapsStorage)]:Clone() 
	if chosenMap:FindFirstChild("Spawn") then
		chosenMap.Parent = workspace
		chosenMap:MakeJoints()
		return chosenMap
	end
end

function minigameModule:spawnPlayers()
	local playersAlive = self.playersAlive
	local spawns = self.currentMap.Spawns:GetChildren()
	for index = 1, #playersAlive do
		local playerData = playersAlive[index]
		playerData.playerHumanoidRoot.CFrame = spawns[math.random(#spawns)].CFrame
	end
end

function minigameModule:runIntermission()
	if settingsModule.intermissionTime > 0 then
		for currentTime = math.floor(settingsModule.intermissionTime), 0, -1 do
			remoteEvent:FireAllClients("Timer", currentTime)
			wait(1)
		end
	end
	remoteEvent:FireAllClients("CeaseGUIs")
end

function minigameModule:getAlivePlayers()
	local playersAlive = {}
	for _, currentPlayer in pairs(playersService:GetPlayers()) do
		local playerCharacter = currentPlayer.Character
		if playerCharacter then
			local playerHumanoidRoot = playerCharacter:FindFirstChild("HumanoidRootPart")
			local playerHumanoid = playerCharacter:FindFirstChild("Humanoid")
			if playerHumanoid and playerHumanoidRoot then
				table.insert(playersAlive, {
					player = currentPlayer,
					playerHumanoid = playerHumanoid,
					playerHumanoidRoot = playerHumanoidRoot
				})
			end
		end
	end
	return playersAlive
end

function minigameModule:isLegalGame()
	if #self:getAlivePlayers() >= settingsModule.minimumPlayers then
		return true
	end
end

function minigameModule:queryGameStart()
	if self.gameRunning then
		return
	elseif self.isPotentialGame() then
		self.gameRunning = true
		remoteEvent:FireAllClients("CeaseGUIs")
		self:runIntermission()

		if self:isLegalGame() then
			if settingsModule.roundDuration > 0 then

				local currentMap = self:chooseMap()
				local mapWeapons = currentMap:FindFirstChild("Weapons")

				local playersAlive = self:getAlivePlayers()
				self.playersAlive = playersAlive

				for index = 1, #playersAlive do
					local currentPlayer = playersAlive[index]
					local backpack = currentPlayer.player.Backpack

					if backpack and mapWeapons then
						for index, weapon in next, mapWeapons:GetChildren() do
							weapon:Clone().Parent = backpack
						end
					end

					local connection
					connection = currentPlayer.playerHumanoid.Died:connect(function()
						connection:disconnect()
						table.remove(playersAlive, index)
						if #playersAlive < 2 then
							local winner = playersAlive[1]
							if winner then
								self:endGame(winner.player.Name .. " has won!", winner.player)
							else
								self:endGame("No one has won!")
							end
						end
					end)
				end

				if mapWeapons then
					mapWeapons:Destroy()
				end

				self:spawnPlayers()		

				remoteEvent:FireAllClients("Message", currentMap.Name .. " was chosen!", 5)

				for currentTime = settingsModule.roundDuration, 0, -1 do
					if not self.gameRunning then
						return
					end
					remoteEvent:FireAllClients("Timer", currentTime)
					wait(1)
				end
				self:endGame("The timer ran out! No one has won!")
			end

		else
			self:endGame("Not enough players alive to begin the round!")
		end
	else
		local remainingPlayers = settingsModule.minimumPlayers - playersService.NumPlayers
		remoteEvent:FireAllClients("Message", "Waiting for " .. remainingPlayers .. " player" .. (remainingPlayers > 1 and "s" or "") .. " to join.")
	end
end

function minigameModule:endGame(outputMessage, winner)
	if self.gameRunning then

		self.gameRunning = false
		self.currentMap:Destroy()
		self.currentMap = nil

		if winner and onWin then
			onWin(winner)
		end

		for index, player in next, playersService:GetPlayers() do
			player:LoadCharacter()
		end

		wait(1)

		remoteEvent:FireAllClients("Message", outputMessage, 5)

		wait(5)

		self:queryGameStart()
	end
end

function minigameModule:removePlayer(player)
	if self.gameRunning then
		for index = 1, #self.playersAlive do
			if self.playersAlive[index].player == player then
				table.remove(self.playersAlive, index)
				if #self.playersAlive <= 1 then
					self:endGame("Not enough players to continue the game.")
				end
				break
			end
		end	
	end
end

playersService.PlayerAdded:connect(function()
	minigameModule:queryGameStart()
end)

playersService.PlayerRemoving:connect(function(player)
	minigameModule:removePlayer(player)
end)

Please use :FindFirstChild() and :WaitForChild() accordingly.

Ok, so as soon as I opened the game I got the error: ServerScriptService.Main:21: attempt to index nil with ‘isPotentialGame’

Oops, remove the local minigameModule = nil that I added to remove orange lines

The one at the top, because when I remove that it makes all of the references of it become unknown