Instance.Destroying fires too late

Destroying is meant to fire before before the instance is parented to nil and its descendants destroyed. According to the documentation: “The Destroying event fires immediately before the Instance or one of its ancestors is destroyed with Instance.Destroy().” However, when listening to Instance.Destroying and then calling :Destroy(), the event handler sees the instance’s parent as nil, even if the handler doesn’t yield.

Under the Instance.Destroying API documentation:

This sample demonstrates how an Instance being destroyed remains in place until the connected function yields.

local part = Instance.new("Part", workspace)
 
local function onPartDestroying()
		print("Before yielding:", part:GetFullName(), #part:GetChildren())
		task.wait()
		print("After yielding:", part:GetFullName(), #part:GetChildren())
end
 
part.Destroying:Connect(onPartDestroying)
 
part:Destroy()

When running this code on a default baseplate, it does not work.

RobloxStudioBeta_Ni6IMuFps8

Expected behavior

I expect the instance to not be parented to nil and its children not destroyed inside the Instance.Destroying handler, as long as the developer doesn’t yield. This matches the expectations set by similar methods like Instance.DescendantRemoving (called before descendant is removed, as opposed to Instance.DescendantRemoved, which is called after the fact)

8 Likes

Hey man, :wave:t2:

I was wondering if you are using Deferred Events?

according to this video and my own experience using Deferred Event mode will cause this unexpected behavior while Immediate Event mode doesn’t

I agree that this behavior is unexpected and inconsistent with naming and documentation

I think the best solution here is to create a custom event wrapper so you have complete control

Maybe for your case you can create your own custom Destroy function that fires an event before calling Destroy on the Instance

2 Likes

Ah yeah, I suspected it was because of deferred events. Since deferred events is now the default for new places, I agree Roblox really should fix this. Appreciate the suggestions in the meantime.

2 Likes

roblox should make it so SignalBehavior is scriptable by plugins only so i dont have to change it every each time from deffered to immediate manually :skull:

1 Like

Deferred hasn’t accounted for events like this in mind, since Destroying, and AncestryChanged (and other similar events) fire before doing the action on the assumption you’ll do everything before the internal thing performs its action.

I dont want to know what happens with PlayerRemoving client side since that can only run until a yield occurs.

Events like this should really ignore deferred signals since they expect a certain shape (which isn’t respected if you defer it), or the internal action doesn’t happen until the event has actually signalled, which has its own issues.

3 Likes

Thanks for the report! We’ll follow up when we have an update for you!

2 Likes

I would like to add onto this bug report if you don’t mind.

Instance.Destroying does not always seem to fire if a object is destroyed on the server but a client script tries to detect if it’s destroyed.

I sometimes do client-sided logic that needs a clean-up procedure when an object is destroyed but when an object is destroyed on the server the event doesn’t seem to fire on the client.

.Destroying does not work at all when using Deferred signal behavior.

3 Likes

Hey guys. Any update on the resolution of this bug?

1 Like

this has been an issue for 10 months and there are still no updates on it, we would really like a fix on this please (another thread made here Incorrect Behavior of Destroying Event in Example Code)

Edit: documentation was changed accordingly

2 Likes

The .Destroying event does work differently with Deferred signal behavior, this is by design at the moment. As mentioned above, the docs have been updated to reflect this new behavior. That said, we are open to your feedback at the Deferred Engine Events: Rollout Update thread!