Editor crash on check(!IsRooted()) in MarkAsGarbage

Hi!

I’m tracking down a crash within the garbage collector system (editor only).

Assertion failed: !IsRooted() [File:…\Engine\Source\Runtime\CoreUObject\Public\UObject\UObjectBaseUtility.h] [Line: 178]

From what I see, when a new object is created, we call MarkAsGarbage to add it in the undo buffer, and then clear the flag.

However, the object is detected as part of the root set, so it crashes.

In 5.6, we have it on the creationg of a UNiagaraScript

FunctionScript = NewObject<UNiagaraScript>(this, FName(*(TRANSLATOR_SET_VARIABLES_UNDERSCORE_STR + NodeGuid.ToString())), RF_Transactional);

Can you suggest what I could do to further debug this, or any solution worth exploring?

Thanks a lot!

Steps to Reproduce
We only saw it from manipulations on the niagara editor and material editor.

So far, it seems to only happen if there is a PIE session in progress.

It happens mostly to our VFX guys.

Here are the manipulations that lead to the crash

  • Enable an emitter (occurences in 5.6.1)
  • Apply in the material editor (last occurence so far in 5.5)

Callstacks seems to be missing, I’m adding them here.

Apply material (5.5)

UnrealEditor_CoreUObject!UObjectBaseUtility::MarkAsGarbage
UnrealEditor_CoreUObject!StaticConstructObject_Internal
UnrealEditor_Engine!NewObject
UnrealEditor_Engine!UMaterialInterface::CreateEditorOnlyData
UnrealEditor_Engine!UMaterialInterface::PostInitProperties
UnrealEditor_Engine!UMaterial::PostInitProperties
UnrealEditor_CoreUObject!FObjectInitializer::PostConstructInit
UnrealEditor_CoreUObject!FObjectInitializer::~FObjectInitializer
UnrealEditor_CoreUObject!StaticConstructObject_Internal
UnrealEditor_CoreUObject!StaticDuplicateObjectEx
UnrealEditor_CoreUObject!StaticDuplicateObject
UnrealEditor_MaterialEditor!FMaterialEditor::UpdateOriginalMaterial
UnrealEditor_MaterialEditor!FMaterialEditor::OnApply 

Enable emitter (5.6)

 	UnrealEditor-CoreUObject.dll!UObjectBaseUtility::MarkAsGarbage() Line 178
 	UnrealEditor-CoreUObject.dll!StaticConstructObject_Internal(const FStaticConstructObjectParameters & Params) Line 4984
 	UnrealEditor-NiagaraEditor.dll!NewObject(UObject *) Line 1927
 	UnrealEditor-NiagaraEditor.dll!UNiagaraNodeAssignment::GenerateScript() Line 346
 	UnrealEditor-NiagaraEditor.dll!UNiagaraNodeAssignment::RefreshFromExternalChanges() Line 87
 	UnrealEditor-NiagaraEditor.dll!UNiagaraScriptSource::RefreshFromExternalChanges() Line 168
 	UnrealEditor-Niagara.dll!FNiagaraEmitterHandle::SetIsEnabled(bool bInIsEnabled, UNiagaraSystem & InOwnerSystem, bool bRecompileIfChanged) Line 148

Hi!

I’d be curious to know what the repro steps are to trigger this. Are you only able to do it in your project, or does this happen also in a new empty project? Does it happen every time, or randomly? If you can send repro steps for a new empty project, I’d be able to see exactly what’s happening on my side and help fix it.

But to guess the problem, it might be that the parent particle system got added to the root set, which then could triggers this crash. Usually, assets that get loaded very early on, during engine initialization, get added to the root set. For example, if you have a C++ class that hard-loads an asset in its constructor via ConstructorHelpers. That is a recipe for a bunch of problems, using PROPERTY class member variables and setting their value in a derived Blueprint asset is the correct method.

Or it might be hard referenced by some other system that early initializes.

Try putting a breakpoint into UNiagaraScript’s C++ constructor and see when it gets created. It might be some other class also, like UNiagaraSystem. There will always be at least the C++ CDO constructed very early on, so ignore that one, but anything else in early engine initialization might indicate the problem.

Thanks for you answer Ari!

  1. I cannot test this in a new project, since we cannot pin point an exact repro.
  2. Randomly, but once it starts happening, it can happen multiple times in a short time. Feels like some data is saved in a problematic state. I am counting on this to attach a debugger the next time a user has the issue.
  3. The repro steps a roughly:
    1. enabling an emitter while PIE is running (with said emitter).
    2. Applying a material (though last time we saw that was in 5.5).
  4. I tried what you suggested without finding any system or script that loads suspiciously early, but will try again more carefully when I have time. I will report back my findings.

Objects being added in the rootset wrongfully did not occur to me (although the error is about that :sweat_smile:). This is useful, I’ll see if I can add checks to spot the error early on.

Since it’s hard to repro, let’s focus on how to catch it when it happens.

You could enable the “prompt for remote debugging” to catch it in a debugger

UE can ask for remote debugging just before crashing / asserting which would help here.

You can turn it on via command line when launching the process: -PromptRemoteDebug or -PromptRemoteDebugEnsure.

And also via config, so everyone in the team gets it. In DefaultEngine.ini:

[Engine.ErrorHandling]

bPromptForRemoteDebugging=True

and / or

bPromptForRemoteDebugOnEnsure=True

Then, when someone catches the crash and that popup shows up, you can get a programmer to walk over or remotely debug their process. See more here: Advanced Debugging in Unreal Engine | Tutorial

If you don’t want it to happen for every crash or ensure, you can also enable it just before that problematic function by putting this before the function where it fails:

FPlatformMisc::SetShouldPromptForRemoteDebugging(true);

and then disable after it.

You can also use FPlatformMisc::SetShouldPromptForRemoteDebugOnEnsure(true) for ensures. Like, for example, if you were to add a custom ensure close to the problematic function that crashes when the object is a part of the root set.

I did not know about this, thanks for the info I will set this up!