TOptional Properties on derived classes don't update with parent

When editing a TOptional property in a Base BP, the change doesn’t propagate to Derived BPs (that have no Instance changes that would override it)

E.g. (As per the repro steps)

Take BP_TOptionalBase and BP_TOptionalDerived where Derived’s parent class is Base

When making an edit to a TOptional property in the base BP the change isn’t reflected in the derived BP.

Steps to Reproduce
I’ve attached a Zip file with a Plugin (used with Stock UE) for everything you need to repro the issue.

When in editor open BP_TOptionalBase and BP_TOptionalDerived

In BP_TOptionalBase make an edit to Raw Property and to Optional Property

In BP_TOptionalDerived see that the Raw Property change propagates whereas the Optional Property change doesn’t

(This is without any changes to the Derived BP so it’s not Instance overriding Default)

Plugin is made in 5.5.4 but same problem is experienced in 5.6.1

Hey, thanks for the repro code. This issue is still present in UE 5.7+ and is primarily an oversight that comes from TOptional’s editor logic differing from other property types. I’ve entered this as bug UE-350636 in our issue tracker. You can keep an eye on that page for progress on the engine fix.

Here is what I’ve found so far. The problem starts when setting/unsetting: the editor path for settingand unsetting the optional value does not propagate the set/unset state to any children. That logic is specific to TOptional and is currently flawed. Callstacks for reference:

     OptionalProperty->MarkSetAndGetInitializedValuePointerToReplace(Addr);
>    UnrealEditor-PropertyEditor.dll!FPropertyHandleOptional::SetOptionalValue(FProperty * NewProperty, const UClass * NewObjectClass) Line 5713    C++
     UnrealEditor-PropertyEditor.dll!FPropertyEditor::OnSetOptionalValue(FProperty * NewProperty, const UClass * NewObjectClass) Line 374    C++ 
     OptionalProperty->MarkUnset(Addr);
>    UnrealEditor-PropertyEditor.dll!FPropertyHandleOptional::ClearOptionalValue() Line 5867    C++
     UnrealEditor-PropertyEditor.dll!FPropertyEditor::OnClearOptionalValue() Line 389    C++ 

I have a half-solution which at least updates the data of loaded children immediately. It doesn’t refresh opened blueprint editors so their view is incorrect until blueprint compilation. Just sharing this in case you want to take the half-solution already to mitigate data loss. In FPropertyHandleOptional::SetOptionalValue() you can make the following modification:

OptionalProperty->MarkSetAndGetInitializedValuePointerToReplace(Addr);
 
// START EDIT
const TArray<UObject*>& AffectedInstances = AffectedInstancesPerObject[i];
for (UObject* Inst : AffectedInstances)
{
	void* InstPropAddr = OptionalProperty->ContainerPtrToValuePtr<void>(Inst);
	OptionalProperty->MarkSetAndGetInitializedValuePointerToReplace(InstPropAddr);
	UE_LOG(LogTemp, Warning, TEXT("Additionally set and initialized optional value on: %s"), *Inst->GetPathName());
}
// END EDIT

Similarly in ClearOptionalValue:

OptionalProperty->MarkUnset(Addr);
 
// START EDIT
const TArray<UObject*>& AffectedInstances = AffectedInstancesPerObject[i];
for (UObject* Inst : AffectedInstances)
{
	void* InstPropAddr = OptionalProperty->ContainerPtrToValuePtr<void>(Inst);
	OptionalProperty->MarkUnset(InstPropAddr);
	UE_LOG(LogTemp, Warning, TEXT("Additionally unset optional value on: %s"), *Inst->GetPathName());	
}
// END EDIT

The details view of derived BPs will be outdated, but any view refresh like on compiling blueprints will correct that. With this solution, at least resaving derived BPs after making a parent BP change will no longer cause them to stop inheriting the value. The full fix will follow later, but hard to say when.

A short update: UE-350636 won’t receive high priority, because TOptional being exposed through the details panel turns out to be a side effect of other work. It’s not officially blueprint supported, for example you can’t add a BP Variable that’s optional. I would consider avoiding using TOptional in blueprints. This will also affect actor workflows: when changing the set/unset state in an actor BP, actor instances loaded in the level editor will also not update immediately.

Reloading the level without resaving would work, as would reloading derived BPs but until UE-350636 is fixed you will encounter data loss if you accidentally resave a derived BP class or an instance in the editor level.

Hi,

Thanks for the quick response and help.

It’s odd to hear that it’s a side effect, “Added support for the TOptional type to UHT” is in the 5.4 release notes

Unreal Engine 5.4 Release Notes | Unreal Engine 5.4 Documentation | Epic Developer Community

I tried integrating the temp fix you gave, and while it does fix my case, it causes crashes in others.

Seemingly when the TOptional is in a TArray (via a UStruct)

It fails the check(GetOwner<UClass>()); in ContainerUObjectPtrToValuePtrInternal (the call added in the temp fix)

“I tried integrating the temp fix you gave, and while it does fix my case, it causes crashes in others.”

Understood. Though that case is fixable, adding full support for TOptional will be a bigger task and I’m going to leave it to system owners to get to that eventually. I would consider not using TOptional for the time being.

“It’s odd to hear that it’s a side effect, “Added support for the TOptional type to UHT” is in the 5.4 release notes”

The use case for which this was implemented did not involve BP inheritance. IMO this release note is misleading, thanks for pointing this out. I’ll see if I can get this corrected to be more specific.