!IsUnreachable() assert in UActorComponent::DoDeferredRenderUpdates_Concurrent — auto-destroyed NiagaraComponent collected by GC mid-pass during SendAllEndOfFrameUpdates (PIE only)

We spawn bAutoDestroy=true non-looping Niagara via UNiagaraFunctionLibrary::SpawnSystem*.

Oncompletion OnSystemComplete→DestroyComponent(); when this coincides with the EOF window, GC appears to

mark the component Unreachable mid-pass.

<br/>

In Update_GameThread (LevelTick.cpp), components are gathered into a raw TArray (GC-invisible), then after a reentrant op (FStaticMeshComponentBulkReregisterContext) the array is iterated WITHOUT re-validation. Also, IsValid() only tests the Garbage flag, not Unreachable.

<br/>

Q. For bAutoDestroy=true Niagara, is caller-side destroy-timing control (spawn with false, then

DestroyComponent() after polling IsComplete(), outside the EOF window) the sanctioned workaround?

재현 방법
No deterministic steps — intermittent. Spawn many bAutoDestroy=true non-looping (naturally

finishing) Niagara via UNiagaraFunctionLibrary::SpawnSystem* → under PIE’s frequent GC, the crash hits

when a completion (OnSystemComplete→DestroyComponent) coincides with the EOF window.

Assert: !IsUnreachable() [ActorComponent.cpp:2593], DoDeferredRenderUpdates_Concurrent() ←

SendAllEndOfFrameUpdates()→Update_GameThread(). Callstack is entirely engine-internal; the component is

always a NiagaraComponent.

Hi,

GC should not be running mid SendAllEndOfFrameUpdates, equally Niagara should not be calling DestroyComponent mid SendAllEndOfFrameUpdates.

Could you provide the full callstacks where you are seeing these occur?

Thanks,

Stu