Error in DuplicateDepedenciesToNewRoot when assembling metahuman character

Hello,

We recently updated Unreal to 5.8.2 and since then, we have an error when trying to assemble a Metahuman Character. The error is the following:

MetaHuman: Error: Cannot copy Common asset ‘CR_PlaceHolder’ an incompatible asset of type ‘/Script/ControlRig.ControlRigBlueprintGeneratedClass’ already exists at the target location. Remove or rename the conflicting asset and try again.

Looks like it comes from the piece of code added in 5.8 from MetahumanCharacterBuild.cpp CheckValidDependencyPackage() that now check on-disk class mismatch.

I think we had some issues related to that pre-5.8 and this is now catched by the code because when I take a look at our /Game/MetaHumans/Common/Animation folder, there are multiple CR_PlaceHolder assets (CR_PlaceHolder_1, CR_PlaceHolder_2, CR_PlaceHolder_3 and so on…).

By tinkering with the code, I managed to determine that the 4 following assets have the same issue when assembling a MetahumanCharacter:

/Game/MetaHumans/Common/Animation/CR_PlaceHolder

/Game/MetaHumans/Common/Common/MetaHuman_ControlRig

/Game/MetaHumans/Common/Face/CR_MetaHuman_HeadMovement_IK_Proc

/Game/MetaHumans/Common/Face/Face_ControlBoard_CtrlRig

They all share the same pattern:

* FMetaHumanCharacterEditorBuild::DuplicateDepedenciesToNewRoot calls UPackageTools::FindOrCreatePackageForAssetType.

* FindOrCreatePackageForAssetType uses the Asset Registry to get the Assets in the existing package, but it returns 2 assets.

[Image Removed]

* This sets bShouldGenerateUniquePackageName to true, which will create a new package with an unique name.

* Then in CheckValidDependencyPackage(), TargetPackage->GetName() != AssetPackagePath returns false, since TargetPackage has an unique id at the end of it’s package name.

* AssetRegistry.GetAssetsByPackageName() gets the two assets in the Package and prints the first one in the error log, despite the second one being the one of the same class of DependencyAsset->GetClass() we’re looking for.

[Image Removed]

The workaround I found is to force delete the four assets above, then execute the Assembly and it works. Metahuman re-create the packages, re-link the references and successfully complete the process. But then, when I re-save these four assets, the error “Cannot copy Common asset ‘CR_PlaceHolder’ an incompatible asset of type ‘/Script/ControlRig.ControlRigBlueprintGeneratedClass’ already exists at the target location.” comes back…

I also checked the Metahuman Character data in the plugin used to do the duplication, but they were not edited by accident on our side.

Do you have any idea on how to fix this issue ?

Thanks in advance,

Guillaume

[Attachment Removed]

Hi Guillaume,

Based on what you reported, something pretty odd is happening in the project when you’re running UAssetRegistryImpl::GetAssetsByPackageName from UPackageTools::FindOrCreatePackageForAssetType. GetAssetsByPackageName should filter out generated classes by default. That’s part of what the bSkipARFilteredAssets argument should do, which is defaulted to true. To reproduce the behaviour that you mentioned, I was only able to do so by passing bSkipARFilteredAssets as false, but even then, my setup failed on the first anim blueprint asset, not only on the control rigs.

Could you do some further debugging in UAssetRegistryImpl::GetAssets to see which codepath is being taken. That should call into EnumerateDiskAssets and eventually into FAssetRegistryState::EnumerateAssets which does the work to find the asset and apply the filtering. When I was debugging, it was this code that was responsible for filtering out the blueprint generated class:

for (const FAssetData* AssetData : AccumulatedResults)
		{
			if (ShouldSkipAssetData(AssetData))
			{
				continue;
			}
			bool bContinueFiltering = Callback(*AssetData);
			if (!bContinueFiltering)
			{
				return true;
			}
		}

That calls the ShouldSkipAssetData lambda, which should call into FFiltering::ShouldSkipAsset and in turn Utils::ShouldSkipAsset. Then it’s this code that should return true to filter out the ControlRigBlueprintGeneratedClass:

const bool bIsCooked = (PackageFlags & PKG_FilterEditorOnly);
		if ((bIsCooked && InSkipCookedClasses.Contains(AssetClass)) ||
			(!bIsCooked && InSkipUncookedClasses.Contains(AssetClass)))
		{
			return true;
		}

So my guess is that maybe your InSkipUncookedClasses list doesn’t contain ControlRigBlueprintGeneratedClass. If you can confirm that’s the case, we’ll be a step forward in working out what’s going wrong.

You also mentioned:

> I think we had some issues related to that pre-5.8 and this is now catched by the code

Can you give me more information on what these issues were?

edit: also what specific release of 5.8 are you on?

Thanks,

Euan

[Attachment Removed]

Adding a screenshot of what my InSkipUncookedClasses list looks like:

[Image Removed]

[Attachment Removed]

Hey Euan,

You’re right ! That’s it !

This is my InSkipUncookedClasses when assembling a Metahuman Character, no ControlRigBlueprintGeneratedClass in sight:

[Image Removed]I set a breakpoint in PopulateSkipClasses to see what was happening and noticed that one of our system is making a call to AssetRegistry.GetAssetsByPath() in its constructor when constructing its DefaultObject.

[Image Removed]This causes the PopulateSkipClasses() to be called early during engine init (with FFiltering::InitializeShouldSkipAsset()), and preventing caching all the needed classes in UE::AssetRegistry::SkipUncookedClasses because they are not loaded yet. bInitializedSkipClasses is set to true, condemning us to get them in the future.

Removing the “FillColorPresetMaps()” line in the constructor fixed the issue. The content of the array looks like yours and there is no more error when assembling the character ! I’ll move the FillColorPresetMaps() call to somewhere else, probably at PostEngineInit.

> I think we had some issues related to that pre-5.8 and this is now catched by the code

We’re currently on 5.8.2.

And this is what we recently had in perforce:

[Image Removed]We had multiple CR_PlaceHolder assets generated by the Metahuman Assembly. Looks like the new error that was added in 5.8 was designed to catch this kind of issue and I’m glad we did !

Thanks a lot !

Guillaume

[Attachment Removed]

Hi Guillaume,

Good to hear that info let you track down what was going wrong and get it all fixed up. I’ll try to find someone on the editor team to discuss this with further, as it seems generally problematic that the skip list is baked in on the first call to FFiltering::InitializeShouldSkipAsset. Any custom code/plugin that does this early in the loading process will run into the same problem, and it’s not an obvious bug to track down.

Thanks,

Euan

[Attachment Removed]