Component deleted from blueprint visible during validation

We have a custom validator that verifies that, if a certain component is part of an actor, it has a tag present in one of the properties. Realising that some blueprints had this component added unnecessarily, it was removed from those blueprints. However, the actors already spawned on levels still fail validation - but only if this validation is run from commandlet. Running validation from the editor passes. We’ve debugged the validator and the actors seen there, when run from the validator, have the components in the OwnedComponents field. If I open this actor in editor, I see that the component is not present. If I manually save the actor in editor, it passes validation. But if I resave the actor using a commandlet - either ResavePackages or WorldPartitionBuilderCommandlet, the problem persists, suggesting to me that commandlets don’t perform some processing on actors after loading.

Is there a way to implement validators and/or run resave so that these actors are saved correctly, without the deleted component? Resaving them by hand would be quite cumbersome and I would like to avoid disabling the validator as it finds actual issues in other actors.

Steps to Reproduce

  1. create a blueprint, add a component to it
  2. spawn the blueprint on a level
  3. create a validator that logs when this component exists
  4. remove the component from the blueprint
  5. run the validator via commandlet
  6. it will log the component for instances of the blueprint
  7. run WorldPartitionBuilderCommandlet to resave the level
  8. run the validator via commandlet
  9. it will still log the component for instances of the blueprint
  10. manually save the instance on the level
  11. run the validator via commandlet
  12. notice that it stops logging the component for that instance

Hi [mention removed]​,

After some investigation we have been able to reproduce the issue. We will see if this bug has been reported previously and if unreal devs have already a solution that we can share with you. Would it be good for you to apply a patch to your engine if a solution is already available? If this bug is still present in unreal development branch, we will report it so that the devs can start working on it.

Best Regards,

Joan

Hello Joan,

Absolutely, a patch would be perfect, thank you!

Hi [mention removed]​,

I’m currently having issues with my computer and it is taking me some extra time. I should be able to give you the fix commit this week, just letting you know. Sorry for the delay.

Best Regards,

Joan

Hi [mention removed]​,

Sorry for the delay. I’ve run the test and in my case I can reproduce the first part of the issue: the validation commandlet does report the actor instances as still having the component, even though the component has already been removed from the Blueprint class.

However, my results differ from yours in the next step. After rebuilding the level using WorldPartitionBuilderCommandlet, the level appears to be rebuilt correctly. When I run the validator again afterwards, the component is no longer reported on the actor instances in the World Partition level.

For reference, here are the commandlets I used for the test::

Validate Commandlet
 
"MyEnginePath\UE_5.6\Engine\Binaries\Win64\UnrealEditor-Cmd.exe" "MyProjectPath\UE_561\UE_561.uproject" -run=DataValidation
Rebuild Commandlet
 
"MyEnginePath\UE_5.6\Engine\Binaries\Win64\UnrealEditor-Cmd.exe" "MyProjectPath\UE_561\UE_561.uproject" "/Game/ValidationRepro/ReproMap" -run=WorldPartitionBuilderCommandlet -builder=WorldPartitionResaveActorsBuilder -SCCProvider=None

This is the validator I am using to check for the component in the actor instances within the World Partition level:

#include "ReproRemovedComponentValidator.h"
 
#include "Engine/World.h"
#include "Engine/Level.h"
#include "GameFramework/Actor.h"
#include "AssetRegistry/AssetData.h"
#include "UE_561/ReproValidationComponent.h"
 
DEFINE_LOG_CATEGORY_STATIC(LogReproValidator, Display, All);
 
bool UReproRemovedComponentValidator::CanValidateAsset_Implementation(
    const FAssetData& InAssetData,
    UObject* InObject,
    FDataValidationContext& InContext) const
{
    return InObject && InObject->IsA<UWorld>();
}
 
EDataValidationResult UReproRemovedComponentValidator::ValidateLoadedAsset_Implementation(
    const FAssetData& InAssetData, UObject* InObject, const UObject* InContext)
{
    UWorld* World = Cast<UWorld>(InObject);
    if (!World || !World->PersistentLevel)
    {
        return EDataValidationResult::NotValidated;
    }
 
    int32 MatchingActors = 0;
 
    for (AActor* Actor : World->PersistentLevel->Actors)
    {
        if (!IsValid(Actor))
        {
            continue;
        }
 
        TInlineComponentArray<UReproValidationComponent*> Components;
        Actor->GetComponents<UReproValidationComponent>(Components);
 
        if (Components.Num() > 0)
        {
            MatchingActors++;
 
            UE_LOG(LogReproValidator, Warning,
                TEXT("Actor %s still contains UReproValidationComponent"),
                *Actor->GetPathName());
 
            AssetFails(
                InContext,
                FText::FromString(
                    FString::Printf(TEXT("Actor '%s' still contains UReproValidationComponent"),
                        *Actor->GetPathName())));
        }
    }
 
    UE_LOG(LogReproValidator, Display,
        TEXT("Validation finished. Actors with component: %d"),
        MatchingActors);
 
    return MatchingActors > 0 ? EDataValidationResult::Invalid
        : EDataValidationResult::Valid;
}
 
bool UReproRemovedComponentValidator::IsEnabled() const
{
    return true;
}

The steps I followed were the following:

1- Create an actor Blueprint and add an actor component to it.

2- Spawn multiple instances of the actor in a World Partition level.

3- Compile and save both the Blueprint and the level.

4- Remove the component from the Blueprint, then compile and save again.

5- Close the editor and run the DataValidation commandlet. At this point, my validator logs that the actor instances in the World Partition level still contain the component.

6- Run the WorldPartitionBuilderCommandlet. The build completes successfully.

7- Run the DataValidation commandlet again. This time the validator reports 0 errors.

Could you please let us know if I may have missed any of your steps? It is also possible that there is some difference between my setup and yours that could explain the issue. It would be helpful if you could try the code I provided and check whether you still encounter the same error.

Best Regards,

Joan