MVVMView : Ensure condition failed: bIsPointerValid == bIsBitfieldValid

Hello,

We make extensive use of view models on our HUD. Several of our widgets rely on view models with their creation type set to Manual.

After upgrading from Unreal Engine 5.4 to 5.5 (specifically 5.5.4), we started encountering the following ensure message when the HUD is created a second time:

Ensure condition failed: bIsPointerValid == bIsBitfieldValid [C:\UE\Engine\Plugins\Runtime\ModelViewViewModel\Source\ModelViewViewModel\Private\View\MVVMView.cpp] [Line: 412]

The source SOMEVIEWMODEL should be valid.

Upon debugging, we found that MVVMView extensions are now being reused during the second creation of the HUD. As a result, some internal states are no longer reset to their defaults. Specifically, for each ViewSource, the bSetManually flag remains true. This causes a different code path to be followed during Construct, ultimately leading to the ensure failure.

To address this, we modified the UninitializeSource function to reset the state of all ViewSources, regardless of whether they were set manually. However, we only release the ViewSource instance if it wasn’t manually set.

Additionally, we reset the ViewSource.RegisteredCount to 0 in UMVVMView::UninitializeSourceBindings.

That said, we’re still unsure if this is the correct approach. Previously, this issue didn’t occur because MVVMView was recreated along with the widget. Now that it’s reused, the problem surfaces.

Below is our modified UninitializeSource function:

`void UMVVMView::UninitializeSource(FMVVMView_SourceKey SourceKey)
{
FMVVMView_Source& ViewSource = Sources[SourceKey.GetIndex()];
const FMVVMViewClass_Source& ClassSource = GeneratedViewClass->GetSource(ViewSource.ClassKey);

if (ViewSource.bSourceInitialized)
{
ViewSource.bSourceInitialized = false;
if (!ViewSource.bSetManually)
{
ClassSource.ReleaseInstance(ViewSource.Source, this);
}

ViewSource.bSetManually = false;
ViewSource.Source = nullptr;
if (ViewSource.bAssignedToUserWidgetProperty)
{
UUserWidget* UserWidget = GetUserWidget();
FObjectPropertyBase* FoundObjectProperty = FindFProperty(UserWidget->GetClass(), ClassSource.GetUserWidgetPropertyName());
if (ensureAlwaysMsgf(FoundObjectProperty, TEXT(“The compiler should have added the property”)))
{
FoundObjectProperty->SetObjectPropertyValue_InContainer(UserWidget, nullptr);
}
ViewSource.bAssignedToUserWidgetProperty = false;
}

ValidSources &= ~ViewSource.ClassKey.GetBit();

#if UE_WITH_MVVM_DEBUGGING
UE::MVVM::FDebugging::BroadcastViewSourceValueChanged(this, ViewSource.ClassKey, SourceKey);
#endif
}
}`

Steps to Reproduce

  • Have a widget using a ViewModel with creation type set to ‘Manual’.
  • Travel to a different level (or even the same one) using the command open

Hi Victor,

We have two relevant changes here that you may want to grab, CL#39052857 and CL#42587574. The second change resets ViewSource.RegisteredCount to 0 as you mentioned, though it sounds like you may have needed some additional fixes here. I’ll check if I can reproduce this in UE5 Main, if so then we can investigate making a similar change on our side.

Best,

Cody

Hi Cody,

We had already tried integrating CL#39052857, but we were still getting the assert.

Now, we’ve also integrated CL#42587574, and it appears to correctly reset RegisteredCount as well. Because of this, we’ve removed the manual reset of RegisteredCount we were doing at the end of UninitializeSourceBindings.

So far, the only way we’ve found to properly reset all states is by using the version of UninitializeSource mentioned above, so we’ll continue using it for now.

Thank you so much for your help and support.