Deleting Multiple LevelInstances Leaves Some in “Unloaded” State Instead of Deleting

When deleting multiple LevelInstance actors at once in the editor, only the first actor is properly deleted, while the others remain stuck in an “Unloaded” state in the World Outliner. This issue persists even when using the latest mainline version of UUnrealEdEngine::DeleteActors().

Reproduction Steps:

  1. Open any map that contains at least two LevelInstance actors (especially World Partition-based maps).
  2. In the World Outliner, select two or more LevelInstances.
  3. Press Delete (or right-click → Edit --> Delete).
  4. Observe the World Outliner.

Expected Result: All selected LevelInstances should be fully deleted (removed from the World Outliner), and their streaming levels garbage collected.

Actual Result:

• Only the first-selected LevelInstance is deleted successfully.

• All subsequent LevelInstances remain in the World Outliner with “Unloaded” status.

• Logs indicate EditorDestroyActor() returns true, and the actor is no longer in the level’s Actors array.

• However, the associated LevelInstance worlds are not garbage collected.

Additional Notes:

• We have cherry-picked and tested with the latest implementation of UUnrealEdEngine::DeleteActors() from the main line (//UE5/Main/Engine/Source/Editor/UnrealEd/Private/EditorActor.cpp #58), but the issue still occurs.

• Using FScopedTransaction properly (at the top of the function) has no effect on the problem.

Steps to Reproduce

  1. Open any map that contains at least two LevelInstance actors (especially World Partition-based maps).
  2. In the World Outliner, select two or more LevelInstances.
  3. Press Delete (or right-click → Edit --> Delete).
  4. Observe the World Outliner.

The cause I discovered:

A live transaction in GEditor->Trans (specifically, UTransBuffer::AddReferencedObjects) was holding a reference to LandscapeStreamingProxy, which in turn kept a reference to the LevelInstance’s outer World. This caused GC to retain the LevelInstance even after deletion.

I initially attempted to resolve this by calling GEditor->Trans->Reset(…), but this was too aggressive and caused all actors to remain in the “unloaded” state instead of being deleted, due to internal transaction state inconsistencies.

I then call GEditor->Trans->Cancel(0) before deleting the actor. This safely ends the current transaction and clears the reference from UTransBuffer, allowing GC to clean up the deleted LevelInstance as expected.

My current workaround is:

`bool UUnrealEdEngine::DeleteActors(const TArray<AActor*>& InActorsToDelete, UWorld* InWorld, UTypedElementSelectionSet* InSelectionSet, const bool bVerifyDeletionCanHappen, const bool bWarnAboutReferences, const bool bWarnAboutSoftReferences)
{

for (AActor* Actor : ActorsToDelete)
{
// Begin of My workaround
if (GEditor && GEditor->Trans)
{
GEditor->Trans->Cancel(0); // Cancel current active transaction
}
// End of My workaround

//If actor is referenced by script, ask user if they really want to delete
ULevelScriptBlueprint* LSB = Actor->GetLevel()->GetLevelScriptBlueprint(true);

}

}`

This ensures that there is no active transaction holding references during the deletion, and both LevelInstances now get deleted correctly.

My questions:

  1. Is this a safe and recommended workaround for this kind of issue?
  2. Could calling Cancel(0) during DeleteActors have any unintended side effects within the editor, especially if other tools rely on transactions at this point?
  3. Is there a better or more “engine-approved” way to ensure that deleted actors aren’t retained due to lingering transactions?

Thanks in advance for any guidance!

Hi,

I managed to reproduce your bug in 5.4, but upon testing UE version to 5.5 and 5.6 it looks like the bug isn’t present using the same steps.

Would updating your UE version be possible for you, or are you looking to keep 5.4 and find a specific engine change?

I can’t speak to some of your questions due to the depth being outside of my knowledge, but I can escalate the case to Epic if you would like insight into it.

For your workaround, possibly testing End instead of Cancel to attempt to close an undo transaction instead of interrupting it could mitigate unintended effects.

I’m unsure of the risk of your workaround, but possibly adding a check to see if the actor is a level instance actor before running your workaround to make it more isolated just in case could be beneficial.

Regards

Hi John,

Thank you for your detailed response.

We are planning to upgrade our project to UE 5.6 within the next 1–2 months, so I might hold off on finalizing our workaround and see if 5.6 resolves the issue as you mentioned. However, I have already cherry-picked and tested the latest version of UUnrealEdEngine::DeleteActors() from the main line (//UE5/Main/Engine/Source/Editor/UnrealEd/Private/EditorActor.cpp revision #58), and unfortunately, the issue still occurs on our end. Therefore, I am not fully relying on the UE 5.6 upgrade as a definitive solution just yet.

I also implemented your suggestion, adding an isolation check to apply the workaround only to LevelInstance actors, and using End() instead of Cancel() to close the transaction, and it works very well.

Thank you for the helpful recommendations.

Glad to hear my recommendations were helpful!

Please let me know if you would like to have this case pushed up to Epic for more specific answers to your questions still (i.e. Regarding a more “engine-approved” way / unintended side effects) or if you’re all set until the 5.6 upgrade.

Thank you.

Thank you John,

We will upgrade to 5.6 soon, and will post the result once I have tested our map in 5.6.