Quick answer: Soft references (TSoftObjectPtr) do not force the target asset to be cooked. Either register the data asset type with the Asset Manager (Project Settings → Asset Manager) or add the directory to Additional Asset Directories To Cook. Without one of these, soft refs to uncooked assets resolve to null in builds.
Here is how to fix Unreal soft references and data assets that resolve to null in shipping builds even though the editor sees them fine. You design abilities or item definitions as DataAssets, store them in DataTables or as TSoftObjectPtr arrays, and the cooker silently excludes them. Players see no enemies, no pickups, no abilities — only fail-fast nullptr crashes.
The Symptom
A TSoftObjectPtr<UAbilityDataAsset> works in PIE. After packaging, the pointer’s LoadSynchronous returns null. The cook log shows the asset is not in the package. Hard-coding a hard reference fixes the issue but is impractical for hundreds of assets.
What Causes This
Soft refs do not create cook dependencies. By design. Otherwise the cooker would pull every potentially referenced asset, defeating the point of soft refs.
No hard reference and no Asset Manager registration. Without either, the asset is not in any cooker reachability path. The cooker excludes it from the build.
DataTable references are sometimes also soft. FDataTableRowHandle stores a soft reference to the table. If only the table itself is hard-referenced but the rows reference assets via soft pointers, those assets may be missed.
Editor-only references. Asset references created in editor utility widgets do not survive packaging.
The Fix
Step 1: Register the data asset type with Asset Manager.
Open Project Settings → Game → Asset Manager. Under Primary Asset Types To Scan, add a new entry:
Primary Asset Type: Ability
Asset Base Class: UAbilityDataAsset
Directories: [/Game/Abilities]
Has Blueprint Classes: false
Is Editor Only: false
Cook Rule: AlwaysCook
This makes the Asset Manager scan the directory at startup and pull in every matching asset. The cooker honors this list.
Step 2: Use Asset Manager APIs to query.
void UMySubsystem::LoadAllAbilities()
{
UAssetManager& AM = UAssetManager::Get();
TArray<FAssetData> assets;
AM.GetPrimaryAssetDataList(FPrimaryAssetType("Ability"), assets);
for (const FAssetData& data : assets)
{
if (UAbilityDataAsset* a = Cast<UAbilityDataAsset>(data.GetAsset()))
{
AllAbilities.Add(a);
}
}
}
Step 3: Or add to Additional Asset Directories To Cook. If you do not want to use Asset Manager, open Project Settings → Packaging and add directories to Additional Asset Directories To Cook. Everything inside is cooked unconditionally.
Step 4: Async load with FStreamableManager.
void AItem::EquipAsync(TSoftObjectPtr<UItemDefinition> itemSoft)
{
UAssetManager& AM = UAssetManager::Get();
FStreamableManager& SM = AM.GetStreamableManager();
SM.RequestAsyncLoad(itemSoft.ToSoftObjectPath(),
FStreamableDelegate::CreateUObject(this, &AItem::OnItemLoaded, itemSoft));
}
void AItem::OnItemLoaded(TSoftObjectPtr<UItemDefinition> itemSoft)
{
if (UItemDefinition* def = itemSoft.Get())
{
ApplyDefinition(def);
}
}
Step 5: Verify the cook. After packaging, open the build folder and look at the .pak content list:
UnrealPak.exe MyGame-Pak.pak -List
Search for your asset name. If absent, registration or directory inclusion is still wrong.
Hard vs Soft Reference Cheat Sheet
// Hard - always cooked, always loaded with owner
UPROPERTY(EditAnywhere)
UItemDefinition* HardItem;
// Soft - cooked only if reachable through Asset Manager or hard ref chain
UPROPERTY(EditAnywhere)
TSoftObjectPtr<UItemDefinition> SoftItem;
// Soft class - same rules but for UClass references
UPROPERTY(EditAnywhere)
TSoftClassPtr<UItemDefinition> SoftClass;
Use hard for small assets always loaded with the owner. Use soft for large content (textures, meshes) you load on demand. Always pair soft refs with Asset Manager registration when the data is not also referenced by something else hard.
“Soft refs save memory but break cook reachability. Asset Manager fills the gap. Without it, the cooker leaves your data behind.”
Related Issues
For DataAsset save issues, see Data Asset Changes Not Saving. For Niagara cook issues, see Niagara Not Rendering.
Asset Manager primary type. Or Additional Directories To Cook. Either way the cooker keeps the file.