Stupid replication issue with ragdolls

Having this really confusing issue where NPC ragdolls aren’t being replicated to the client
What i’ve tried so far:

  • Tried the different options of PhysicsImprovedSleep and PhysicsSteppingMethod
  • Tried with & without the humanoid state stuff, makes no difference
  • Messed around with network ownership - makes no difference. currently I have it nil
  • Tried without the anchoring, also tried never unanchoring the npc, which works but is impractical
  • Seems to replicate properly slightly more often if the attach.CFrame part is commented out, however this is impractical since it turns the NPC into a spinning ball of flesh
  • Tried running each iteration on its own thread, seems to make no difference
  • Commented out all other NPC code - there is no code running on this NPC except for the code that spawns it, and the death handling.

PROBABLY IMPORTANT: If I increase the time the NPC is anchored for (lets say 0.5 seconds) it ALWAYS replicates properly to the client, but i shouldn’t have to do that. If i have the wait timer at something inbetween like 0.33s, i see the NPC ragdoll on the client for a sec, but then it becomes stiff after it unanchors.

On the client: Stiff as a board
image

On the server: Ragdolls properly
image

Current script:

self.connect[`npcDeath`]=self.hum.Died:Connect(function()
		if self.dead then return end
		self.dead=true
		
		self.stopPathing:Fire()
		debris:AddItem(self.npc,10)
		
		self.hum:SetStateEnabled(Enum.HumanoidStateType.GettingUp,false)
		self.hum:SetStateEnabled(Enum.HumanoidStateType.Ragdoll,true)
		self.hum:ChangeState(Enum.HumanoidStateType.Physics)
		
		for _,track:AnimationTrack in self.hum.Animator:GetPlayingAnimationTracks()do
			track:Stop()
		end
		
		self.root.Anchored=true
		for _,v in self.npc:GetDescendants()do
			if v:IsA(`Motor6D`)then
				local ballSocket=Instance.new(`BallSocketConstraint`)
				local attach0=Instance.new(`Attachment`)
				local attach1=Instance.new(`Attachment`)
				
				attach0.Parent=v.Part0
				attach1.Parent=v.Part1
				
				ballSocket.Parent=v.Parent
				ballSocket.Attachment0=attach0
				ballSocket.Attachment1=attach1
				
				attach0.CFrame=v.C0
				attach1.CFrame=v.C1
				
				--movement range
				ballSocket.LimitsEnabled=true
				ballSocket.TwistLimitsEnabled=true
				--ballSocket.UpperAngle=45
				
				v:Destroy()
			end
		end
		task.wait(0.25)
		self.root.Anchored=false
		
		--yeet the npc a little
		self.root:ApplyImpulse(vector.create(rng:NextInteger(-25,25),1000,rng:NextInteger(-25,25)))
		

                --the code below has no impact on the ragdoll
		task.wait(3)
		for _,con:RBXScriptConnection in self.connect do
			if con and con.Disconnect then
				con:Disconnect()
			end
		end
		
		--remove connection references from the table, and remove self
		self.connect=nil
		self=nil
		
		local currentSpawned=spawnedNPCs:GetAttribute(`CurrentSpawned`)
		spawnedNPCs:SetAttribute(`CurrentSpawned`,currentSpawned-1)
	end)

on the rare occasion that it replicates the ragdoll properly, if I go near the npc it becomes stiff again, which is crazy because the network ownership is so nil i couldn’t make it any more nil if i tried. i’ve even added a second for loop which ensures every part is nil
image

for now, my solution is just to set the NPC’s network ownership to the player who killed it. unfortunately this means other players will usually not see the ragdoll, but it works for now