Unreal Engine 5.4 Released

Hi Everyone,

Whilst testing out our upgrade from 5.3.2 → 5.4.0, I found that I can no longer produce a package of the game. The packaging process hits an ensure in the following place:

LogOutputDevice: Error: Ensure condition failed: CurrentNum == InitialNum  [File:D:\build\++UE5\Sync\Engine\Source\Runtime\Core\Public\Containers\Array.h] [Line: 253]
LogOutputDevice: Error: Array has changed during ranged-for iteration!
LogOutputDevice: Error: Stack:
LogOutputDevice: Error: [Callstack] 0x00007ffbd7843f79 UnrealEditor-Engine.dll!ULevel::DetachAttachAllActorsPackages() [D:\build\++UE5\Sync\Engine\Source\Runtime\Engine\Private\Level.cpp:4249]
LogOutputDevice: Error: [Callstack] 0x00007ffbd8beeab5 UnrealEditor-Engine.dll!UWorld::PreSaveRoot() [D:\build\++UE5\Sync\Engine\Source\Runtime\Engine\Private\World.cpp:1524]
LogOutputDevice: Error: [Callstack] 0x00007ffbdb2ee27f UnrealEditor-CoreUObject.dll!UE::SavePackageUtilities::CallPreSaveRoot() [D:\build\++UE5\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\SavePackage\SavePackageUtilities.cpp:693]
LogOutputDevice: Error: [Callstack] 0x00007ffbdb30df41 UnrealEditor-CoreUObject.dll!UPackage::Save2() [D:\build\++UE5\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\SavePackage2.cpp:3097]
LogOutputDevice: Error: [Callstack] 0x00007ffbdb30e5d9 UnrealEditor-CoreUObject.dll!UPackage::Save() [D:\build\++UE5\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\SavePackage.cpp:20]
LogOutputDevice: Error: [Callstack] 0x00007ffbd2b33ea7 UnrealEditor-UnrealEd.dll!UEditorEngine::Save() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\EditorEngine.cpp:4837]
LogOutputDevice: Error: [Callstack] 0x00007ffbd28ba027 UnrealEditor-UnrealEd.dll!UCookOnTheFlyServer::SaveCookedPackage() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\CookOnTheFlyServer.cpp:6172]
LogOutputDevice: Error: [Callstack] 0x00007ffbd289e128 UnrealEditor-UnrealEd.dll!UCookOnTheFlyServer::PumpSaves() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\CookOnTheFlyServer.cpp:4738]
LogOutputDevice: Error: [Callstack] 0x00007ffbd28c71e7 UnrealEditor-UnrealEd.dll!UCookOnTheFlyServer::TickMainCookLoop() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\CookOnTheFlyServer.cpp:1464]
LogOutputDevice: Error: [Callstack] 0x00007ffbd28c6624 UnrealEditor-UnrealEd.dll!UCookOnTheFlyServer::TickCookByTheBook() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\CookOnTheFlyServer.cpp:1346]
LogOutputDevice: Error: [Callstack] 0x00007ffbd25a1de0 UnrealEditor-UnrealEd.dll!UCookCommandlet::RunCookByTheBookCook() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\Commandlets\CookCommandlet.cpp:555]
LogOutputDevice: Error: [Callstack] 0x00007ffbd25630cd UnrealEditor-UnrealEd.dll!UCookCommandlet::CookByTheBook() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\Commandlets\CookCommandlet.cpp:508]
LogOutputDevice: Error: [Callstack] 0x00007ffbd257e910 UnrealEditor-UnrealEd.dll!UCookCommandlet::Main() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\Commandlets\CookCommandlet.cpp:249]
LogOutputDevice: Error: [Callstack] 0x00007ff7e6db95fd UnrealEditor-Cmd.exe!FEngineLoop::PreInitPostStartupScreen() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\LaunchEngineLoop.cpp:4194]
LogOutputDevice: Error: [Callstack] 0x00007ff7e6daf606 UnrealEditor-Cmd.exe!GuardedMain() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Launch.cpp:136]
LogOutputDevice: Error: [Callstack] 0x00007ff7e6daf8ea UnrealEditor-Cmd.exe!GuardedMainWrapper() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:118]
LogOutputDevice: Error: [Callstack] 0x00007ff7e6db2dc4 UnrealEditor-Cmd.exe!LaunchWindowsStartup() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:258]
LogOutputDevice: Error: [Callstack] 0x00007ff7e6dc88c4 UnrealEditor-Cmd.exe!WinMain() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:298]

We are using the level streaming system extensively, and have all our levels set to use “External Actors”.

Attaching a debugger to the packaging process shows that its hitting this ensure whilst renaming "Child Actor"s from their “Parent Actor” external package, to the Level as the package.

So, inside the “rename” call at line 4267 of Level.cpp, it is changing the level->Actors array (which this code is currently iterating over):

	for (AActor* Actor : Actors)
		{
			if (Actor)
			{
				if (UPackage* ActorExternalPackage = Actor->GetExternalPackage())
				{
					Actor->DetachExternalPackage();

					// Process objects found in the source actor package
					TArray<UObject*> Objects;
					const bool bIncludeNestedSubobjects = false;

					GetObjectsWithPackage(ActorExternalPackage, Objects, bIncludeNestedSubobjects, RF_NoFlags, EInternalObjectFlags::Garbage);
					for (UObject* Object : Objects)
					{
						if (Object != Actor && Object->GetFName() != NAME_PackageMetaData)
						{
							// Move objects in the destination level package
							Object->Rename(nullptr, LevelPackage, REN_ForceNoResetLoaders);

							// Keep track of which package this object really belongs to
							ObjectsToExternalPackages.Emplace(Object, ActorExternalPackage);
						}
					}
				}
			}
		}

All this code is brand new to 5.4 compared to 5.3. I got around this bug by making any level containing child actors have internal actors again. I think this would be fairly reproducible, and if so, likely means any project using Child Actors cannot also use External Actor packages.

3 Likes