I'm At Loss, no clue what makes this crash occur, could someone help why that assert could happen

We added new enemy, skeleton meshes are loaded asynchronously, we have already 6 types of enemies that never did such a crash but with this new enemy this crash happens very rarely, but right before his spawn so i assume its because of async batch request, i changed things with async load but cant solve it yet, i post the crash and the code where that async request happens(its pretty long, since i added a lots of UE_LOG):
Crash on this assert:

Code:

void UPrimaryDataAssetsManager::AsyncLoadEnemy(const ECharacterType InCharacter, const EGameMode InGameMode, const bool bCanEvolve, TFunction<void()> InCallBack)
{
	if (!GetCanAsyncLoadHappen()) return;
	const FCharacterContainer& CharacterContainer = GetCharacterData(InCharacter);
	TArray<FSoftObjectPath> PathsToLoad;
	const TObjectPtr<UPA_CharacterContainer> CharContainer = CharacterContainer.GetCharacterContainer();
	if (!IsValid(CharContainer))
	{
		UE_LOG(LogTemp, Error, TEXT("Invalid CharacterContainer for character %s"), *UEnum::GetValueAsString(InCharacter));
		return;
	}
	if (!CharContainer->CharacterClass.IsNull()) PathsToLoad.Add(CharContainer->CharacterClass.ToSoftObjectPath());
	else UE_LOG(LogTemp, Warning, TEXT("CharacterClass is invalid for character %s"), *UEnum::GetValueAsString(InCharacter));
	if (!CharContainer->CharacterMesh.IsNull()) PathsToLoad.Add(CharContainer->CharacterMesh.ToSoftObjectPath());
	else UE_LOG(LogTemp, Warning, TEXT("CharacterMesh is invalid for character %s"), *UEnum::GetValueAsString(InCharacter));
	EWeapon Weapon = GetWeaponByCharacter(InCharacter);
	const TObjectPtr<UPA_WeaponContainer> WeaponContainer = GetWeaponData(Weapon);
	if (!IsValid(WeaponContainer))
	{
		UE_LOG(LogTemp, Error, TEXT("Invalid WeaponContainer for weapon %s"), *UEnum::GetValueAsString(Weapon));
		return;
	}
	if (!WeaponContainer->WeaponClass.IsNull()) PathsToLoad.Add(WeaponContainer->WeaponClass.ToSoftObjectPath());
	else UE_LOG(LogTemp, Warning, TEXT("WeaponClass is invalid for weapon %s"), *UEnum::GetValueAsString(Weapon));
	if (!WeaponContainer->HandsMesh.IsNull()) PathsToLoad.Add(WeaponContainer->HandsMesh.ToSoftObjectPath());
	else UE_LOG(LogTemp, Warning, TEXT("HandsMesh is invalid for weapon %s"), *UEnum::GetValueAsString(Weapon));
	EWeapon SingularWeapon = GetSingularWeapon(Weapon);
	if (SingularWeapon != EWeapon::None)
	{
		const TObjectPtr<UPA_WeaponContainer> SingularWeaponContainer = GetWeaponData(SingularWeapon);
		if (IsValid(SingularWeaponContainer))
		{
			if (!SingularWeaponContainer->WeaponClass.IsNull()) PathsToLoad.Add(SingularWeaponContainer->WeaponClass.ToSoftObjectPath());
			else UE_LOG(LogTemp, Warning, TEXT("SingularWeaponClass is invalid for weapon %s"), *UEnum::GetValueAsString(SingularWeapon));
			if (!SingularWeaponContainer->WeaponMesh.IsNull()) PathsToLoad.Add(SingularWeaponContainer->WeaponMesh.ToSoftObjectPath());
			else UE_LOG(LogTemp, Warning, TEXT("SingularWeaponMesh is invalid for weapon %s"), *UEnum::GetValueAsString(SingularWeapon));
		}
	}
	else if (!WeaponContainer->WeaponMesh.IsNull()) PathsToLoad.Add(WeaponContainer->WeaponMesh.ToSoftObjectPath());
	else UE_LOG(LogTemp, Warning, TEXT("WeaponMesh is invalid for weapon %s"), *UEnum::GetValueAsString(Weapon));
	TArray<FSoftObjectPath> ValidPaths;
	for (const FSoftObjectPath& Path : PathsToLoad) if (!Path.GetAssetPathString().IsEmpty()) ValidPaths.Add(Path);
	if (ValidPaths.IsEmpty())
	{
		UE_LOG(LogTemp, Warning, TEXT("No valid paths to async load for character %s"), *UEnum::GetValueAsString(InCharacter));
		return;
	}
	for (const FSoftObjectPath& Path : ValidPaths) UE_LOG(LogTemp, Warning, TEXT("Path: %s"), *Path.ToString());
	TWeakObjectPtr WeakWorld = GetWorld();
	TSharedPtr<FStreamableHandle> Handle = UAssetManager::GetStreamableManager().RequestAsyncLoad(ValidPaths, [this, WeakWorld, SingularWeapon, Weapon, InCharacter, InGameMode, bCanEvolve, InCallBack]
	{
		if (WeakWorld.IsValid() && IsAsyncAssetWorldValid(WeakWorld.Get())) AsyncLoadEnemyCallback(SingularWeapon, Weapon, InCharacter, InGameMode, bCanEvolve, InCallBack);
		else UE_LOG(LogTemp, Warning, TEXT("World no longer valid during AsyncLoadEnemy callback for character %s"), *UEnum::GetValueAsString(InCharacter));
	});
	AddAsyncHandle(Handle);
}

If anyone has suggestions i will be glad, since i’m running out of ideas… Thanks.

Hi,

I’d always use .IsNull rather than .IsEmpty as IsNull checks it points to a valid asset rather than simply containing some characters of a string (including empty spaces)

You’re passing in other data which could be getting cleared by the time the async load has finished, such as the weapon data, moving the IsValid checks on these to inside the async load callback may be helpful. I’d also pass in a WeakThis as you’re calling AsyncLoadEnemyCallback on this after the async call.

Next I’d suggest that you load the editor up fresh, go and open the asset that’s crashing and then check the logs to see if there’s any errors listed in that asset. Have you attached visual studio to find out exactly which line is crashing here, is it inside the RequestAsyncLoad in engine code itself?

1 Like

Hi,

I used debug mode in jetbrains IDE, and it would crash without showing the line where it crashed, just that crash log just in IDE itself and assembly code && memory addresses. So had to go that its associated with async, tho i did one more change i had 2 RequestAsyncLoad with batch of paths, they could intercept with each other, maybe that was the trigger of that crash, after that i used stress test with 100 async load batch requests(20 / second) and force GC clear every 0.1s, didn’t got crash tried on editor / standalone / packaged so perhaps it is solved, such “unknown crashes” are the hardest to solve :grinning_face: especially when they not trigger every time, thanks for the suggestions i use .IsNull as well and yeah i should send weakThis.