Help with making this A* algorthm actually function

I have a A* pathfinding algorythm located within a module script that could be required()'d

The pathfinding algorythm would just open nodes at an aburtary direction until it hits a wall

Idk what to do

Is this problem occuring just because of my incorrect maths or logic?

--strategic_oof

local Pathing01 = {}

local NodeId=0

local function RoundToNearest(v: Vector3, Size: number): Vector3
	return Vector3.new(
		math.round(v.X/Size)*Size,
		math.round(v.Y/Size)*Size,
		math.round(v.Z/Size)*Size
	)
end

local function HeuristicFunction(a: Vector3, b: Vector3): number
	return math.abs(a.X - b.X) + math.abs(a.Y - b.Y) + math.abs(a.Z - b.Z)
end

local function FindOpenNode(Pos: Vector3, Data: {}): {} -- a function to find a node in the open set since we use arrays
	for i,v in Data.OpenNodes do
		if v.Position==Pos then
			return v
		end
	end
end

function Pathing01.CreateParameters(): {}
	local t={
		--AgentCanClimb=false,
		--AgentCanJump=true,
		--AgentMovementSpeed=16,
		--AgentJumpPower=50,
		--AgentHight=5,
		--AgentWidth=4,
		IgnoreParts={},	
		GridSize=2
	}
	--50 / 6.94444444444 = 7.2
	--t.JumpDistance =  2 * t.AgentJumpPower * t.AgentMovementSpeed / workspace.Gravity
	
	--t.Actions={
	--	"Jump",
	--	"Climb",
	--	"Swim"
	--}
	
	t.ValidMovements={ --the more movements the more computer resourses the algorithm needs
		Vector3.new(1,0,0) * t.GridSize,
		Vector3.new(-1,0,0) * t.GridSize,
		
		Vector3.new(0,0,1) * t.GridSize,
		Vector3.new(0,0,-1) * t.GridSize,
		
		Vector3.new(1,0,1) * t.GridSize,
		Vector3.new(-1,0,-1) * t.GridSize,
		
		Vector3.new(-1,0,1) * t.GridSize,
		Vector3.new(1,0,-1) * t.GridSize
	}
	
	--print(t.ValidMovements)
	
	return t
end

--function Pathing01.CreateBlankAction(Data: {}): {}
--	local Action={
--		Name=""
--	}
--	table.insert(Data.Actions,Action)

--	return Action
--end

function Pathing01.CreateNode(a: Vector3, b: Vector3, ParentNode: {}, GCost: number, Data: {}): {}
	local Node={}
	Node.Position=a
	Node.ParentNode=ParentNode
	
	Node.GCost=GCost
	Node.HCost=HeuristicFunction(a,b)
	Node.FCost=GCost+Node.HCost
	
	if not Data.LowestFCost[1] then
		Data.LowestFCost=Node
	end
	if Node.FCost<Data.LowestFCost.FCost then
		Data.LowestFCost=Node
	end
	
	table.insert(Data.OpenNodes,Node)
	Node.I=NodeId
	NodeId+=1
	
	local Ball=Instance.new("Part")
	Ball.Shape=Enum.PartType.Ball
	Ball.Size=Vector3.new(.8,.8,.8)
	Ball.Position=Data.LowestFCost.Position
	Ball.Anchored=true
	Ball.CanCollide=false
	Ball.CanQuery=false
	Ball.Material=Enum.Material.Neon
	Ball.BrickColor=BrickColor.White()
	Ball.Parent=workspace
	
	--Node.Open=true
	
	return Node
end

function Pathing01.CheckPosOccupied(Pos: Vector3, Data: {}): boolean
	if Data.Params.IgnoreParts[1] then		
		local op=OverlapParams.new()
		op.FilterDescendantsInstances=Data.Params.IgnoreParts
		op.FilterType=Enum.RaycastFilterType.Exclude
		
		if workspace:GetPartBoundsInBox(CFrame.new(Pos),Vector3.new(Data.Params.AgentWidth*.9,Data.Params.AgentHight*.9,Data.Params.AgentWidth*.9),op)[1] then
			return true
		end		
	else	
		if workspace:GetPartBoundsInBox(CFrame.new(Pos),Vector3.new(Data.Params.AgentWidth*.9,Data.Params.AgentHight*.9,Data.Params.AgentWidth*.9))[1] then
			return true
		end	
	end
	return false
end

function Pathing01.OpenNode(Node: {}, Data: {})
	--Node.Open=false
	for i, v in pairs(Data.OpenNodes) do
		if v.I==Node.I then
			table.remove(Data.OpenNodes,i)
			table.insert(Data.ClosedNodes,Node)
			break
		end
	end
	
	local Ball=Instance.new("Part")
	Ball.Shape=Enum.PartType.Ball
	Ball.Size=Vector3.new(1,1,1)
	Ball.Position=Data.LowestFCost.Position
	Ball.Anchored=true
	Ball.CanCollide=false
	Ball.CanQuery=false
	Ball.Material=Enum.Material.Neon
	Ball.BrickColor=BrickColor.Red()
	Ball.Parent=workspace
	
	for i, v in Data.Params.ValidMovements do
		local Pos=Node.Position+v
		if Pathing01.CheckPosOccupied(Pos,Data)==false then			
			local CostToNeighbour=Node.GCost+(Node.Position-Pos).Magnitude
			local Neighbour=FindOpenNode(Pos,Data)
			print(Neighbour)
			local NeighbourGCost=Neighbour and Neighbour.GCost or 0
			
			if CostToNeighbour<NeighbourGCost or not Neighbour then			
				Pathing01.CreateNode(Pos,Data.EndPos,Node,CostToNeighbour,Data)
			end	
		end
	end
	
end

function Pathing01.ComputePath(StartPos: Vector3,EndPos: Vector3,Parameters: {})
	StartPos=RoundToNearest(StartPos, Parameters.GridSize)
	EndPos=RoundToNearest(EndPos, Parameters.GridSize)
	
	local Data={}
	--Data.Actions={}
	Data.Params=Parameters
	
	Data.OpenNodes={}
	Data.ClosedNodes={}

	Data.LowestFCost={}
	
	Data.StartPos=StartPos
	Data.EndPos=EndPos
	
	Data.StartNode=Pathing01.CreateNode(StartPos,EndPos,nil,0,Data) Data.LowestFCost=Data.StartNode
	
	local A=1000
	local a=A
	
	Pathing01.OpenNode(Data.StartNode, Data)
	
	while Data.OpenNodes[1] do
		--task.wait()
		a-=a
		if a<=0 then
			task.wait()
			a=A
		end
		
		Pathing01.OpenNode(Data.LowestFCost, Data)
		if Data.LowestFCost.Position==EndPos then
			break
		end
		
	end
	
	print("Found Path")
	local FinalNodes={}
	
	while Data.LowestFCost do
		task.wait()
		
		local Ball=Instance.new("Part")
		Ball.Shape=Enum.PartType.Ball
		Ball.Size=Vector3.new(2,2,2)
		Ball.Position=Data.LowestFCost.Position
		Ball.Anchored=true
		Ball.CanCollide=false
		Ball.CanQuery=false
		Ball.Material=Enum.Material.Neon
		Ball.BrickColor=BrickColor.new("Lime green")
		Ball.Parent=workspace
		
		table.insert(FinalNodes,Data.LowestFCost.Position)
		Data.LowestFCost=Data.LowestFCost.ParentNode
	end
	
	print("Done Path")
	
	return FinalNodes
end

return Pathing01