Need help - attempt to index nil with 'Position' - Block System with Prediction Blocks

  1. What do you want to achieve? Block Building System with Prediction Blocks

  2. What is the issue? I’m getting a very annoying error in my code.

  3. What solutions have you tried so far? Used prints, looked around on the dev forum, etc.


Hey all! I’m currently experiencing an issue with my code.
LocalScript:

local PlaceBlockEvent = script.Parent:WaitForChild("PlaceBlock")

local equipped = false
local uis = game:GetService("UserInputService")
local mouse = game.Players.LocalPlayer:GetMouse()
local character = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()
local cam = workspace.CurrentCamera


local function findClosestPart(preview)
	local lowestMagParts = {}
	local currentPart = nil
	local currentClosestDir = nil
	local currentClsoestmag = nil 
	for _,v in pairs(game.Workspace.PartsFolder:GetDescendants()) do
		if v:IsA("BasePart") then
			local magnitude1 = (character.PrimaryPart.Position - v.Position).Magnitude
			if magnitude1 <= 25 then
				table.insert(lowestMagParts, v)
			end
		end
	end
	local lowestMagnitude = nil
	for _,v in pairs(lowestMagParts) do
		if v:IsA("BasePart") then
			local mouse3DPos = character.PrimaryPart.Position + (mouse.Hit.Position - character.PrimaryPart.Position).Unit * (character.PrimaryPart.Position - v.Position).Magnitude
			local mag = (v.Position - mouse3DPos).Magnitude
			if not lowestMagnitude then
				lowestMagnitude = mag
				currentPart = v
				continue
			end
			if mag < lowestMagnitude then
				lowestMagnitude = mag
				currentPart = v
			end
		end
	end

	local surfaceIDs = {
		top = currentPart.Position + Vector3.new(0,25,0),
		bottom = currentPart.Position - Vector3.new(0,25,0),
		left = currentPart.Position - Vector3.new(25,0,0),
		right = currentPart.Position + Vector3.new(25,0,0),
		front = currentPart.Position - Vector3.new(0,0,25),
		back = currentPart.Position + Vector3.new(0,0,25),
	}



	for surfaceId, pos in pairs(surfaceIDs) do
		local mag = ((character.PrimaryPart.Position + (mouse.Hit.Position - character.PrimaryPart.Position).Unit * 25) - pos).Magnitude
		if not currentClsoestmag then
			currentClsoestmag = mag
			currentClosestDir = surfaceId
			continue
		end
		if mag < currentClsoestmag then
			currentClsoestmag = mag
			currentClosestDir = surfaceId
		end
	end
	if currentClosestDir ~= nil then
		table.clear(lowestMagParts)
		return currentPart, currentClosestDir
	end

end

local connection = nil

script.Parent.Equipped:Connect(function()
	if equipped == false then
		equipped = true
		print("Equiped == true")
		local clonePreview = Instance.new("Part")
		clonePreview.Parent = game.Workspace:WaitForChild("PartsPreview")
		clonePreview.Name = script.Parent.Parent.Name.."Preview"
		clonePreview.Transparency = 1
		clonePreview.Size = Vector3.new(3,3,3)
		clonePreview.CanCollide = false
		clonePreview.Anchored = true
		print("ClonePreview Activated")
		local selection = Instance.new("SelectionBox", clonePreview)
		selection.Visible = true
		selection.Adornee = clonePreview
		selection.LineThickness = 0.05
		selection.Color3 = Color3.fromRGB(0,0,0)
		print("Made selection box")
		for _,v in pairs(game.Workspace.PartsPreview:GetChildren()) do
			if v ~= clonePreview then
				v:Destroy()
				print("Destroyed 'v'")
			end
		end
		mouse.TargetFilter = clonePreview
		task.defer(function()
			print("what is task.defer")
			while wait() do
				if equipped == true then
					local mouseX,mouseY,mouseZ = mouse.Hit.X, mouse.Hit.Y, mouse.Hit.Z
					local mouseTarget = mouse.TargetSurface
					if mouse.Target ~= nil then
						print("mouse target")
						if mouseTarget == Enum.NormalId.Top then
							clonePreview.CFrame = (CFrame.new(mouse.Target.Position + Vector3.new(0,3, 0))) --- the 3 is the size of the block
						elseif mouseTarget == Enum.NormalId.Bottom then
							clonePreview.CFrame = (CFrame.new(mouse.Target.Position - Vector3.new(0,3, 0))) --- the 3 is the size of the block
						elseif mouseTarget == Enum.NormalId.Left then
							clonePreview.CFrame = (CFrame.new(mouse.Target.Position - Vector3.new(3, 0,0))) --- the 3 is the size of the block
						elseif mouseTarget == Enum.NormalId.Right then
							clonePreview.CFrame = (CFrame.new(mouse.Target.Position + Vector3.new(3,0, 0))) --- the 3 is the size of the block
						elseif mouseTarget == Enum.NormalId.Front then
							clonePreview.CFrame = (CFrame.new(mouse.Target.Position - Vector3.new(0,0, 3))) --- the 3 is the size of the block
						elseif mouseTarget == Enum.NormalId.Back then
							clonePreview.CFrame = (CFrame.new(mouse.Target.Position + Vector3.new(0,0, 3))) --- the 3 is the size of the block
						end
					elseif mouse.Target == nil then
						local closestPart, direction = findClosestPart(clonePreview)
						if tostring(direction) == "top" then
							clonePreview.CFrame = (CFrame.new(closestPart.Position + Vector3.new(0,3, 0))) --- the 3 is the size of the block
						elseif tostring(direction) == "bottom" then
							clonePreview.CFrame = (CFrame.new(closestPart.Position - Vector3.new(0,3, 0))) --- the 3 is the size of the block
						elseif tostring(direction) == "left" then
							clonePreview.CFrame = (CFrame.new(closestPart.Position - Vector3.new(3,0,0))) --- the 3 is the size of the block
						elseif tostring(direction) == "right" then
							clonePreview.CFrame = (CFrame.new(closestPart.Position + Vector3.new(3,0, 0))) --- the 3 is the size of the block
						elseif tostring(direction) == "front" then
							clonePreview.CFrame = (CFrame.new(closestPart.Position - Vector3.new(0,0, 3))) --- the 3 is the size of the block
						elseif tostring(direction) == "back" then
							clonePreview.CFrame = (CFrame.new(closestPart.Position + Vector3.new(0,0, 3))) --- the 3 is the size of the block
						end
						closestPart = nil
						direction = nil
					end	
				end
			end
		end)

		connection = mouse.Button1Down:Connect(function()
			if equipped == true then
				for _,v in pairs(game.Workspace:WaitForChild("PartsFolder"):GetDescendants()) do
					if v:IsA("BasePart") then
						if clonePreview.Position == v.Position then
							return
						end
					end
				end

				local primaryPart = clonePreview.CFrame
				PlaceBlockEvent:FireServer(primaryPart)
			end

		end)
	end
end)

script.Parent.Unequipped:Connect(function()
	if equipped == true then
		equipped = false
		if workspace.PartsPreview:FindFirstChild(script.Parent.Parent.Name.."Preview") then
			local preview = workspace.PartsPreview:FindFirstChild(script.Parent.Parent.Name.."Preview")
			preview:Destroy()
		end
	end
	connection:Disconnect()
	connection = nil
end)

Script:

local event = script.Parent.PlaceBlock
local part = game.ReplicatedStorage:WaitForChild("BlockNew") ---- name of the part in the replicated storage you want to clone for the block placement system

event.OnServerEvent:Connect(function(plr, pos)
	local Clone = part:Clone()
	Clone.Parent = game.Workspace:WaitForChild("PartsFolder")
	Clone.CFrame = pos
end)

Here is what it needs:
Place a Local Script in a Tool.

Place a Normal script in the tool.

Place a Folder named “PartsFolder” in the workspace and place all the parts you want in the map.

Place a Folder named “PartsPreview” in the workspace for the prediction block.

Place a Remote event named “PlaceBlock” in the tool.

Can anyone help? Here’s a video and the error in the output:
robloxapp-20220303-2052269.wmv (2.3 MB) (sorry, i used roblox recorder)

image
Thanks all!
EDIT: Error happens when mouse is off map.

If the issue is happening when your mouse is off the map, then I can only assume that there is no part being set as currentPart therefore there is no Position property. You could probably get rid of this error by just doing a check to see if currentPart == nil before the table at line 41.

That solves the error message. Thanks!