ensure triggered after changing component class and compile

It looks like a false positive ensure.

[Attachment Removed]

Steps to Reproduce
The class needed:

UCLASS()
class AMySkeletalMeshActor : public ASkeletalMeshActor
{
    GENERATED_BODY()

public:
    AMySkeletalMeshActor();
    
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay")
    TObjectPtr<UStaticMeshComponent> StaticMesh{};
};
AMySkeletalMeshActor::AMySkeletalMeshActor()
{
    StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>("StaticMesh");
    
    StaticMesh->SetupAttachment(GetSkeletalMeshComponent());
}

Steps to Reproduce

  1. create a blueprint from AMySkeletalMeshActor and SAVE it
  2. create blueprint component class from USkeletalMeshComponent: “BP_SkeletalComponentTypeA”
  3. change the component class of SkeletalMeshComponent to BP_SkeletalComponentTypeA
  4. hit compile
  5. the ensure should be triggered

the log should looks like:

Ensure condition failed: GIsTransacting [File:D:\U\Engine\Source\Runtime\Engine\Private\Components\SceneComponent.cpp] [Line: 1615]

Component ‘BP_SkeletalComponentTypeA_C /Engine/Transient.SkeletalMeshComponent0_REPLACEMENT_029A806746CBCE917532CE9E133F2191_147450’ has ‘StaticMeshComponent /Engine/Transient.World_2:PersistentLevel.NewBlueprint1_C_0.StaticMesh’ in its AttachChildren array, however, ‘StaticMeshComponent /Engine/Transient.World_2:PersistentLevel.NewBlueprint1_C_0.StaticMesh’ believes it is attached to ‘BP_SkeletalComponentTypeA_C /Engine/Transient.World_2:PersistentLevel.NewBlueprint1_C_0.SkeletalMeshComponent0’

[2026.01.05-17.28.02:675][ 18]LogOutputDevice: Error: Ensure condition failed: GIsTransacting [File:D:\U\Engine\Source\Runtime\Engine\Private\Components\SceneComponent.cpp] [Line: 1615]

Component ‘BP_SkeletalComponentTypeA_C /Engine/Transient.SkeletalMeshComponent0_REPLACEMENT_029A806746CBCE917532CE9E133F2191_147450’ has ‘StaticMeshComponent /Engine/Transient.World_2:PersistentLevel.NewBlueprint1_C_0.StaticMesh’ in its AttachChildren array, however, ‘StaticMeshComponent /Engine/Transient.World_2:PersistentLevel.NewBlueprint1_C_0.StaticMesh’ believes it is attached to ‘BP_SkeletalComponentTypeA_C /Engine/Transient.World_2:PersistentLevel.NewBlueprint1_C_0.SkeletalMeshComponent0’

[2026.01.05-17.28.02:675][ 18]LogStats: FDebug::EnsureFailed - 0.001 s

[2026.01.05-17.28.04:103][ 18]LogSceneComponent: Error: Component ‘BP_SkeletalComponentTypeA_C /Engine/Transient.SkeletalMeshComponent0_REPLACEMENT_029A806746CBCE917532CE9E133F2191_147450’ has ‘StaticMeshComponent /Engine/Transient.World_2:PersistentLevel.NewBlueprint1_C_0.StaticMesh’ in its AttachChildren array, however, ‘StaticMeshComponent /Engine/Transient.World_2:PersistentLevel.NewBlueprint1_C_0.StaticMesh’ believes it is attached to ‘BP_SkeletalComponentTypeA_C /Engine/Transient.World_2:PersistentLevel.NewBlueprint1_C_0.SkeletalMeshComponent0’

[Attachment Removed]

Hello [mention removed]​,

Thanks for the detailed report. I was able to reproduce the ensure locally in UE 5.7 as well as in a recent UE5-Main source build (CL 49553709) following the same steps you described.

It appears this is triggered during Blueprint compilation, when the editor is performing component replacement and cleans up transient components during garbage collection. The old component instance can retain stale entries in its AttachChildren array while the attached child component has already been reattached to the new component instance. When the replacement component is later destroyed, USceneComponent::OnComponentDestroyed() detects this attachment mismatch and emits the ensure.

The ensure reports a real inconsistency but it appears the current check assumes this only occurs during transactions (GIsTransacting).

I’ll continue digging into this and follow up.

Best,

Francisco

[Attachment Removed]

Hello [mention removed]​,

Sorry for the delay. Following up on my previous message, I confirmed this ensure is firing during GC triggered by Blueprint compilation, and not in a transaction context.

If you are on a source build, a temporary editor-only workaround is to locally relax the ensureAlwaysMsgf(GIsTransacting, …) in USceneComponent::OnComponentDestroyed() to also allow GC context.

In SceneComponent.cpp:

#if WITH_EDITORONLY_DATA
							const bool bAllowMismatchContext = GIsTransacting || GarbageCollecting();
							// If we are in the middle of a transaction it isn't entirely unexpected that an AttachParent/AttachChildren pairing is wrong
							if (!ensureAlwaysMsgf(bAllowMismatchContext, TEXT("Component '%s' has '%s' in its AttachChildren array, however, '%s' believes it is attached to '%s'"), *GetFullName(), *Child->GetFullName(), *Child->GetFullName(), *Child->GetAttachParent()->GetFullName()))
#endif

I’ve verified this avoids the ensure in a UE5-Main source build at CL 49719251.

I’m going to report this issue internally and get back to you soon. In the meantime, please let me know if this change unblocks your workflow.

Best,

Francisco

[Attachment Removed]

Hi [mention removed]​

Thanks for your investigating, I confirmed the ensure is gone.

Best,

Sun

[Attachment Removed]

Hello [mention removed]​,

Glad to hear the workaround helped. I’ve gone ahead and registered this issue internally so the engine team can take a look. You should be able to track it at the following link once it becomes public: Unreal Engine Issues and Bug Tracker (UE\-360919)

In the meantime, you can continue using the workaround to avoid the ensure. If you have further questions regarding this case, feel free to let me know. Otherwise, I’ll proceed with closing the case.

Best,

Francisco

[Attachment Removed]