Server not sending correct enemy data to client

My TD enemies randomly get stuck, because the server is not sending the correct values to the client, and the client stops moving them. Any way I could fix this?

I have narrowed it down to the function in the replicator.update(), and the enemy positioning is retuning nil. Still have no idea how to fix it

Here is the code:
Replicator:

--!native
--[[
      __   _  _                                   
  _____  __/ /_ | || |  ___                             
 / _ \ \/ / '_ \| || |_/ __|                            
|  __/>  <| (_) |__   _\__ \                            
 \___/_/\_\\___/   |_| |___/      _   _                 
 _ __  _ __ ___   __| |_   _  ___| |_(_) ___  _ __  ___ 
| '_ \| '__/ _ \ / _` | | | |/ __| __| |/ _ \| '_ \/ __|
| |_) | | | (_) | (_| | |_| | (__| |_| | (_) | | | \__ \
| .__/|_|  \___/ \__,_|\__,_|\___|\__|_|\___/|_| |_|___/
|_|                                                     
]]
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local replicator = {}
replicator.enemies = {}
replicator.pathTable = {}
local BezierPath = require(ReplicatedStorage.Packages:WaitForChild("BezierPath"))
local BridgeNet = require(ReplicatedStorage.Packages:WaitForChild("bridgenet2"))
local enemyclass = require(ServerStorage:WaitForChild("EnemyClass"))
local packetBridge = BridgeNet.ServerBridge("enemyReplication")
--packetBridge.Logging = true
local createBridge = BridgeNet.ServerBridge("enemyCreation")
local deleteBridge = BridgeNet.ServerBridge("enemyDeletion")
local deleteEvent = ReplicatedStorage.deletedCompletedEnemy

--[=[ 
@class replicator

This handles enemy Replication, sends packets to the client, so the client can render and position
All the functions in this module handle enemies, and do things like damage or heal effects.
This module also handles creating enemies.

]=]


--[=[
@function setUp
This function sets up the Replicator, which connects BindableEvent
to deleteEnemies, and reset the EnemyCount.

@within replicator

]=]
replicator.setUp = function(_)
	deleteEvent.Event:Connect(function(hash)
		replicator.enemies[hash] = nil
		replicator.enemyCount -= 1
	end)
	replicator.enemyCount = 0
end

--[=[
@function createnavpath
This function creates an path with the BezierPath Module.
This function is called for each path in the map.

@param nodefolder Folder
@param index number

@within replicator
]=]
replicator.createnavpath = function(nodefolder: Folder, index)
	local nodePositions = { nodefolder.enemyspawn.Position }

	for i = 1, #nodefolder:GetChildren() - 2 do
		table.insert(nodePositions, nodefolder[i].Position)
	end

	table.insert(nodePositions, nodefolder.exit.Position)
	local pathtable = {
		["path"] = BezierPath.new(nodePositions, 3),
		["nodefolder"] = nodefolder,
	}
	replicator.pathTable[index] = pathtable
end

--[=[
@function getEnemyCount
Retrives the amount of enemies active

@within replicator
]=]
replicator.getEnemyCount = function()
	return replicator.enemyCount
end

--[=[
@function getTargetingData

Compiles an table with all the enemies, 
with condensed info like the index of translation, the position, the health, and the translated index.

@within replicator
]=]
replicator.getTargetingData = function()
	task.desynchronize()
	local enemyData = {}
	for hash, enemy: enemyclass.enemy in pairs(replicator.enemies) do
		table.insert(enemyData, { hash, enemy.position, enemy.health, enemy.translated })
	end
	task.synchronize()
	return enemyData
end

--[=[
@function enemyEffect

Changes an property in the enemy with the hash applied.
If the effect is health, than it checks if the health is under 0, and if it is, deletes the enemy.
TODO give cash to everyone based on enemy

@param hash string
@param effect any
@param new any

@within replicator
]=]
replicator.enemyEffect = function(hash, effect, new)
	local enemy = replicator.enemies[hash]
	if enemy then
		enemy[effect] = new
		if effect == "health" then
			if enemy["health"] <= 0 then
				deleteBridge:Fire(BridgeNet.AllPlayers(), hash)
				replicator.enemyCount -= 1
				replicator.enemies[hash] = nil
			end
		end
	end
end

--[=[
@function getSingleEnemy

SelfExplanatory, retrives an single enemy with the hash provided

@param enemyHash string

@within replicator
]=]
replicator.getSingleEnemy = function(enemyHash)
	local enemy = replicator.enemies[enemyHash]
	return enemy
end

--[=[
@function update

Compiles all the enemies into one condensed table, with the CFrame. Than, using bridgeNet2, sends
the infomation to the client, so it can be rendered on the client.

@within replicator
]=]

replicator.update = function()
	local enemyData = {}
	for hash, enemy: enemyclass.enemy in pairs(replicator.enemies) do
		enemyData[hash] = enemy.position
	end
	packetBridge:Fire(BridgeNet.AllPlayers(), enemyData)
end

--[=[
@function addEnemy

Creates an enemy, and adds it to the replicator table in the module. Than, 
fires an bridge to the client to create an enemy, and increases the enemyCount.

@param enemyName string
@param pathNum number

@within replicator
]=]

replicator.addEnemy = function(enemyName, pathNum)
	local eClass = enemyclass.create(enemyName, replicator.pathTable[pathNum])
	createBridge:Fire(BridgeNet.AllPlayers(), { eClass["hash"], eClass["class"] })
	replicator.enemyCount += 1
	local hash = eClass["hash"]
	replicator.enemies[hash] = eClass
end

return replicator

EnemyClass:

--!native
--!strict
local class = {}
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local BezierPath = require(ReplicatedStorage.Packages:WaitForChild("BezierPath"))
local enemystats = require(ServerStorage:WaitForChild("EnemyStats"))
local bosshealthbar = ReplicatedStorage.AddHealthBar
local AbilityManager = require(ServerStorage.AbilityManager)
local Enemies = ReplicatedStorage.Enemies
local HashCreator = require(ServerStorage.HashCreator)
local refresh_rate = 0.1
class.__index = class

export type enemy = {
	speed: number,
	health: number,
	hash: string,
	position: CFrame,
	updateConnection: RBXScriptConnection,
}

function class.create(enemyName, path: BezierPath.Path)
	ReplicatedStorage.DebugValues.EnemyCount.Value += 1
	local self = setmetatable({}, class)
	self.path = path
	self.position = CFrame.new(0,0,0)
	self.class = enemyName
	self.StartTime = os.clock()
	local enemyData = enemystats.get(enemyName)
	self.speed = enemyData.speed
	self.health = enemyData.health
	self.hash = HashCreator.retriveHash()
	self.renderID = 1
	local _, boundingBox = Enemies[enemyName]:GetBoundingBox()
	local sizeAddition = boundingBox.Y / 2
	local rotationalOffset
	local offset = math.random(-1, 1)
	if enemyData.modifiers["boss"] then
		bosshealthbar:FireAllClients(enemyData.name, self, self.health)
	end
	if enemyData.rotationOffset ~= nil then
		rotationalOffset = enemyData.rotationOffset
	else
		rotationalOffset = Vector3.zero
	end
	if enemyData["abilities"] then
		task.spawn(function()
			for ability, _ in pairs(enemyData["abilities"]) do
				AbilityManager.register("enemies", ability, self)
			end
		end)
	end
	self.updateConnection = task.spawn(function()
		local PreviousTime = os.clock()
		self.translated = 0
		while self.translated < 1 do
			task.desynchronize()
			self.translated += (os.clock() - PreviousTime) * self.speed / path["path"]:GetPathLength()
			PreviousTime = os.clock()
			local transformedcframe: CFrame = path["path"]:CalculateUniformCFrame(self.translated)
				* CFrame.new(offset, sizeAddition, 0)
				* CFrame.Angles(rotationalOffset.X, rotationalOffset.Y, rotationalOffset.Z)
			task.synchronize()
			self.position = transformedcframe
			task.wait(refresh_rate)
			task.synchronize()
		end
		ReplicatedStorage.DebugValues.EnemyCount.Value -= 1
		if self.health > 0 then
			ReplicatedStorage.BaseHealth.Value -= self.health
			self.health = 0
		end
	end)
	return self
end

function class:damage(damage)
	local clampedDamage = math.clamp(self.health - damage, 0, 9999999999)
	self.health -= clampedDamage
	if self.health <= 0 then
		class.health = 0
	end
end


return class

Client:

local Players = game:GetService("Players")


local player = Players.LocalPlayer
repeat
	task.wait()
until player:WaitForChild("loaded").Value == true
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Map = ReplicatedStorage:WaitForChild("Map")
local Enemies = ReplicatedStorage:WaitForChild("Enemies")
local loadedEnemies = {}
local Workspace = game:GetService("Workspace")
local MapObject = Workspace:WaitForChild(Map.Value)
local BridgeNet2 = require(ReplicatedStorage.Packages.bridgenet2)
local enemyPacketBridge = BridgeNet2.ReferenceBridge("enemyReplication")
local enemyCreationBridge = BridgeNet2.ReferenceBridge("enemyCreation")
local enemyDeletionBridge = BridgeNet2.ReferenceBridge("enemyDeletion")
local RunService = game:GetService("RunService")
local cframeData = {}
local function createEnemy(content)
	local hash, name = content[1], content[2]
	local enemyModel: Model = Enemies:FindFirstChild(name):Clone()
	enemyModel.Name = hash
	enemyModel.Parent = MapObject.enemies
	loadedEnemies[hash] = enemyModel.PrimaryPart
	local animation = enemyModel.Animations.walk
	local track = enemyModel.AnimationController.Animator:LoadAnimation(animation)
	track:Play()
end

local function deleteEnemy(content)
	local enemy = loadedEnemies[content]
	enemy.Parent:Destroy()
	loadedEnemies[content] = nil
end
local alpha = 0
local function updatePosition(delta)
	local Parts = {}
	local CFrames = {}
	local index = 1
	for hash, cframe in pairs(cframeData) do
		local enemyPrimary = loadedEnemies[hash]
		alpha = math.clamp(delta / 0.1, 0,1)
		Parts[index] = enemyPrimary
		CFrames[index] = enemyPrimary.CFrame:Lerp(cframe, alpha)
		index += 1
	end
	task.synchronize()
	Workspace:BulkMoveTo(Parts, CFrames, Enum.BulkMoveMode.FireCFrameChanged)
end

local function updateData(content)
	cframeData = content
end
enemyCreationBridge:Connect(createEnemy)
enemyPacketBridge:Connect(updateData)
enemyDeletionBridge:Connect(deleteEnemy)
RunService.Heartbeat:ConnectParallel(updatePosition)

Thanks in Advance!

Here is an video of the glitch happening:

I’m unsure why it doesn’t work nor what what BridgeNet or packetBridge is but, ive heard that are limitations with remote events.

^^
this post states that remote events only can be fired 20 times per second, and it seems to me that you have alot more than 20 enemies.

We have one remote that sends all the tables. Also, it’s not bridgenet. The server doesn’t compile all the enemies correctly. Some enemies return nil in their position. So it’s the function replicator.update()

Also said remote was fired 10 times a second.

Before sending the position data to the remote event, it returns nil?

Yes, the cframe is nil before sending to bridgenet2

There might be something wrong with

self.updateConnection = task.spawn(function()
		local PreviousTime = os.clock()
		self.translated = 0
		while self.translated < 1 do
			task.desynchronize()
			self.translated += (os.clock() - PreviousTime) * self.speed / path["path"]:GetPathLength()
			PreviousTime = os.clock()
			local transformedcframe: CFrame = path["path"]:CalculateUniformCFrame(self.translated)
				* CFrame.new(offset, sizeAddition, 0)
				* CFrame.Angles(rotationalOffset.X, rotationalOffset.Y, rotationalOffset.Z)
			task.synchronize()
			self.position = transformedcframe
			task.wait(refresh_rate)
			task.synchronize()
		end
		ReplicatedStorage.DebugValues.EnemyCount.Value -= 1
		if self.health > 0 then
			ReplicatedStorage.BaseHealth.Value -= self.health
			self.health = 0
		end
	end)

It’s the only place where enemy.position is set. Check if it’s ever set to nill there.

its not nil on that. sorry i should prob give u more info on this.

I know that the problem is EnemyReplicator. When i check the position of the frozen enemy on the server, the position is still updating. replicator.update() is not compiling all the enemies correctly, and some enemies in the compiled table returns nil.