Variant Manager Bug

Hi,

We are using the Variant Manager to capture actor properties into presets, batch edit the properties, and then apply them back at runtime. However, during usage we discovered an issue: after saving, sometimes the Blueprint classes inside the Variant Manager are lost, which causes the asset to become corrupted.

There is a very simple way to reproduce this problem:

Create a level, create a preset, drag in any actor, then right-click to bind a function. At this point, a UI appears that allows jumping to the Blueprint. However, after editing these, if I rename the Level Variant Sets, save, and then restart the engine, when I try to open this function binding again, it will show that the Blueprint is corrupted and cannot be opened.

We recorded a simple video to reproduce this issue:

https://drive.google.com/file/d/1E2seK4bMaajmbY-XLW43gKWSd63wJz-Y/view?usp=sharing

We would like to know how we should fix this issue.

Hello [mention removed]​,

Apologies for the delayed response, and thank you for the detailed report and repro video.

I was able to reproduce this issue in both UE 5.6.1 and the current UE 5.7.0 preview build. Could you please confirm whether the same behavior occurred in previous UE 5.x versions as well?

I’ll run additional tests on my end before confirming the bug and submitting it to Epic for review.

I’ll update you here once I have more information.

Best regards,

Francisco

Hi,

Has there been any progress on this issue? We need a temporary workaround to fix it; otherwise, our workflow cannot proceed normally.

Hi [mention removed]​,

After reviewing the engine code, I found that this issue stems from how ULevelVariantSets serializes its internal Director Blueprint references. When a function caller is added, the asset creates a Director Blueprint with the ULevelVariantSetsFunctionDirector class. However, during operations like rename or duplicate, the Director’s GeneratedClass reference isn’t properly re-assigned to the new asset, causing the renamed or duplicated asset to retain invalid references to the original which leads to corruption after saving or restarting.

As a temporary workaround, you can patch the engine to automatically fix up the Director ownership and class references after these operations.

Add the following to LevelVariantSets.h:

#if WITH_EDITOR
	virtual void PostLoad() override;
	virtual void PostDuplicate(EDuplicateMode::Type) override;
	virtual void PostEditChangeChainProperty(struct FPropertyChangedChainEvent& PropertyChangedEvent) override; // optional
	virtual void PostRename(UObject* OldOuter, const FName OldName);
 
	void FixupDirectorOwnership();
#endif

And include the following implementation in LevelVariantSets.cpp:

void ULevelVariantSets::PostLoad()
{
	Super::PostLoad();
	
	FixupDirectorOwnership();
	SubscribeToDirectorCompiled();
}
 
void ULevelVariantSets::PostDuplicate(EDuplicateMode::Type Mode)
{
	Super::PostDuplicate(Mode);
	
	FixupDirectorOwnership();
}
 
void ULevelVariantSets::PostRename(UObject* OldOuter, const FName OldName)
{
	Super::PostRename(OldOuter, OldName);
	
	FixupDirectorOwnership();
}
 
 
void ULevelVariantSets::PostEditChangeChainProperty(FPropertyChangedChainEvent& E)
{
	Super::PostEditChangeChainProperty(E);
	FixupDirectorOwnership();
}
 
void ULevelVariantSets::FixupDirectorOwnership()
{
	UBlueprint* BP = Cast<UBlueprint>(DirectorBlueprint);
	if (!BP) { DirectorClass = nullptr; return; }
 
	if (BP->GetOuter() != this)
	{
		BP->Rename(nullptr, this, REN_DontCreateRedirectors | REN_DoNotDirty);
	}
 
	UPackage* Pkg = BP->GetOutermost();
	UBlueprintGeneratedClass* GC = Cast<UBlueprintGeneratedClass>(BP->GeneratedClass);
 
	if (GC && GC->GetOuter() != Pkg)
	{
		GC->Rename(nullptr, Pkg, REN_DontCreateRedirectors | REN_DoNotDirty);
	}
	if (GC && GC->ClassGeneratedBy != BP)
	{
		GC->ClassGeneratedBy = BP;
	}
 
	if (!GC || GC->GetOuter() != Pkg || GC->ClassGeneratedBy != BP)
	{
		FKismetEditorUtilities::CompileBlueprint(BP);
		GC = Cast<UBlueprintGeneratedClass>(BP->GeneratedClass);
	}
 
	if (DirectorClass && DirectorClass != GC)
	{
		WorldToDirectorInstance.Empty();
	}
	DirectorClass = GC;
 
	if (UPackage* ThisPkg = GetOutermost()) { ThisPkg->MarkPackageDirty(); }
 
}

With these changes in place and the editor rebuilt, you will be able to perform operations like duplicate or rename on the desired LevelVariantSets asset. In the case of renaming, you may still see an empty package left behind from the old name when renaming. This old asset can be safely deleted after restarting the editor.

Please let me know if this solution helps your case and unblocks your workflow.

I’ll also file a bug report so this can be addressed in a future engine update.

Best,

Francisco

Hello again [mention removed]​,

I’m glad to hear the workaround helped. I’ve submitted a bug report for this issue so that the internal engine team can investigate and implement an official fix. In the meantime, you can continue using the provided workaround without concern.

Once the issue is published, you’ll be able to track its status on the Unreal Engine issue tracker at: Unreal Engine Issues and Bug Tracker (UE\-350458)

I’ll go ahead and close this case for now, but please feel free to reply here if you need any follow-up on this topic or open a new case for any other questions.

Best,

Francisco

I don’t have any other engine versions on my computer, but I can reproduce this issue in versions 5.4 through 5.6.

Thank you very much. We’ll try the modifications you suggested.

We’ll follow up with you later to see if the issue has been resolved.

Hi,

​We tested it, and the solution works. After renaming the asset and restarting the engine, the issue no longer occurs.

The only minor issue is that the old name is not automatically removed, so you need to manually run Update Redirector References to clean it up.

However, this doesn’t have much of an impact.