Setting a Frames parent to nil in a PlayerGui in ClientMode also sets the childrens parent to nil

I’ve attached a repro file.

This is only a bug in online mode or in server-test-mode client as far as I know
Setting a frame in a PlayerGui’s parent to nil after both the child and the parent have loaded also sets all of the frame’s children to nil.

The following code reproduces the same glitch with several different parameters.

-- Parent/Unparent child is gone! Poof!
do
	local Frame = script.Parent:WaitForChild("Frame")
	Frame:WaitForChild("Child") -- Guarantees replication
	
	Frame.Parent = nil
	Frame.Parent = script.Parent
	
	print(Frame.Child)
end	

-- See if memory affects it
do
	local Frame = script.Parent:WaitForChild("Frame")
	Frame:WaitForChild("Child") -- Guarantees replication
	local Child = Frame.Child -- Store in memory

	print(Frame.Child) --> Child
	Frame.Parent = nil
	print(Child.Parent)  --> nil
	-- Expected Output: Frame

	print(Frame.Child) --> ERROR:  Child is not a valid member of Frame
end


-- Original repro:
do
	local Frame = script.Parent:WaitForChild("Frame")
	Frame:WaitForChild("Child") -- Guarantees replication
	
	print(Frame.Child) --> Child
	Frame.Parent = nil
	print(Frame.Child) --> ERROR
end	

Where the following structure is occurs:

[code]
Structured as:
ClassName|Name

PlayerGui|PlayerGui
LocalScript|LocalScript
Frame|Frame2
Frame|Child2[/code]

Setup
[list=1]
[]Open up ROBLOX studio
[
]Insert a ScreenGui into the PlayerGui
[]Inside of the ScreenGui insert a frame and a local script
[
]Set the local scripts source to the repro above
[*]Inside of the frame insert another frame and name it “Child”
[/list]

Repro
[list=1]
[*]Launch ROBLOX studio in solo test mode. The script prints out

Child Child Frame Child
[]Launch a server with one client
[
]The script prints out
[/list]

16:03:58.384 - Child is not a valid member of Frame 16:03:58.385 - Script 'Players.Player1.PlayerGui.ScreenGui.Repro', Line 9 16:03:58.385 - Stack End

Notes
It doesn’t matter if the child is in Lua memory or not, as demonstrated by the repro above.

The expected behavior is that the Frame maintains its children-parent hierarchy even when parented to nil. I’ve been using this to cut down on rendering and event costs when I have a template.

I suspect this error has to do with the latest update where :WaitForChild() now works on non-data-child parented objects. Ironically, it never loads the child.

Setting the parent back to the data model does not reset the children into existing.

The root of this problem is not a recent regression: Any instance that is initially replicated from the server to a client underneath the Players service will have this recursive deleting behavior.

However, we may have recently changed StarterGui so that those instances qualify for this special logic. The ideal fix would be to not have this surprise recursive un-parenting for instances that come over under the Players service, or at least to not have it apply to StarterGui elements, but that will take some time to implement.

One short term fix is to enable Workspace.FilteringEnabled; this will actually cause the StarterGui to be set up on the client instead of the server, and so the instances will not be tagged for recursive un-parenting.

Thanks LordRugdumph,

I actually have FilteringEnabled in my game. However, a script enables it right after the server starts. This might negate the effect of having instances being sent instead of created.

For now my workaround is to just not nil out the parent. When the parts are untagged, is there a GC loop executed on them in the event that they have an event connected to them? (I’ve also noted this could be an issue with connecting to Player objects, where you can memory leak ROBLOX with events). If so, this could be potentially deadly to a games long term performance.

In any event, thank you for the response.

What? Are you sure? That contradicts what’s on this thread.