Quick answer: Your widget blueprint was never cooked into the package. Unreal only includes assets reachable via hard references from a map or explicitly listed under Additional Asset Directories to Cook. Fix it by adding a hard-reference property (TSubclassOf<UUserWidget>) on a loaded class, or by listing the widget’s content directory in Project Settings — then rebuild.

You test your HUD, pause menu, or game-over screen in PIE and everything looks perfect. You package the project, launch the executable, and the widget simply does not appear — no error, no crash, just nothing. This is one of the most disorienting packaging bugs in Unreal Engine because the failure is completely silent: the engine found no asset to display and moved on without logging anything obvious.

The Symptom

The tell-tale signs are consistent: the widget works in the editor (Play In Editor or Standalone Game mode launched from the editor), but in a packaged .exe or platform build the screen is empty. Sometimes the widget container exists but has no children visible. In C++ code, CreateWidget() returns a valid pointer but the widget renders nothing, or returns nullptr outright when using a dynamically-looked-up class.

A secondary symptom: the widget does appear in a Development build but not a Shipping build, or it appeared in an earlier package and stopped showing up after you moved the Blueprint to a new content folder.

What Causes This

Unreal’s cooker only includes assets that can be reached by the cooker’s dependency walk. It starts from your project’s default maps (listed in Project Settings → Maps & Modes → Default Maps), follows every hard reference recursively, and packages everything it finds. Assets that are referenced only through soft references, dynamic string lookups, or that live in directories not in the cooking list are silently excluded.

There are four distinct root causes for a missing widget:

  1. Soft reference never resolved at cook time. A TSoftClassPtr<UUserWidget> or TSoftObjectPtr is not automatically cooked unless something else loads it. The cooker records the path but only cooks the asset if it’s reachable from a hard reference chain or from the AssetManager’s primary asset list.
  2. FindClass() / StaticLoadClass() with a bare string. Class lookups by string path work in the editor (all assets are in memory) but silently return nullptr in a packaged build when the class was never cooked.
  3. The widget’s directory is excluded from cooking. If you placed the widget inside a folder not reachable from any map and not in Additional Asset Directories to Cook, it never makes it into the package.
  4. AssetManager / PrimaryAssetLabel not configured. Projects using the AssetManager for on-demand loading must explicitly label widget blueprints or their enclosing bundles as primary assets, otherwise they are stripped.

The Fix

Option 1: Add a Hard Reference

The most reliable fix is to give your widget a hard reference from a class that is always cooked. Your GameMode, GameInstance, or a data-only Blueprint already referenced from the default map are all good anchors.

In C++, add a TSubclassOf property:

// MyGameMode.h
UPROPERTY(EditDefaultsOnly, Category = "UI")
TSubclassOf<UUserWidget> HUDWidgetClass;

// MyGameMode.cpp  BeginPlay
void AMyGameMode::BeginPlay()
{
    Super::BeginPlay();
    if (HUDWidgetClass)
    {
        UUserWidget* HUD = CreateWidget<UUserWidget>(
            GetWorld(), HUDWidgetClass);
        if (HUD) HUD->AddToViewport();
    }
}

Then open your BP_MyGameMode Blueprint, find the HUD Widget Class property in the Details panel, and assign your widget Blueprint there. Because this property is serialized with the GameMode asset, which is hard-referenced from the default map, the cooker will follow the reference and cook your widget.

In Blueprint you can do the exact same thing with a Class Reference variable (set type to Class, subclass of User Widget) and assign it in the Blueprint defaults. A Blueprint class variable with a concrete assignment is a hard reference.

Option 2: Additional Asset Directories to Cook

If you have many widgets spread across a content folder and don’t want to enumerate every one, add the folder path in Project Settings → Packaging → Additional Asset Directories to Cook. Paths are relative to your content root, for example:

/Game/UI/Widgets
/Game/UI/Menus

This tells the cooker to include every asset inside those directories regardless of whether anything references them. It is slightly broader than a hard reference — everything in the folder is cooked — so keep the folders focused to avoid bloating the package.

Option 3: Fix FindClass() Calls

If your code loads a widget class by string, replace the lookup with a proper asset reference. The broken pattern looks like this:

// BROKEN in packaged builds
UClass* WidgetClass = FindClass(
    "/Game/UI/WBP_HUD.WBP_HUD_C");

// ALSO BROKEN: only works if asset is already in memory
UClass* WidgetClass = StaticLoadClass(
    UUserWidget::StaticClass(), nullptr,
    "/Game/UI/WBP_HUD.WBP_HUD_C");

FindClass() only searches already-loaded classes. StaticLoadClass() can load from disk, but only if the asset was cooked. The correct fix is to avoid the string lookup entirely and use a TSubclassOf UPROPERTY set in the editor, as shown above. If you absolutely need dynamic loading (for a mod system, for example), use a TSoftClassPtr and register the asset as a primary asset in the AssetManager so the cooker knows to include it.

Option 4: AssetManager and PrimaryAssetLabels

For projects that use the AssetManager for on-demand streaming, you need to declare your widget types as primary assets. In Project Settings → Asset Manager, add an entry under Primary Asset Types to Scan:

Alternatively, drop a PrimaryAssetLabel asset inside your UI folder (right-click in the Content Browser → Miscellaneous → Data Asset → PrimaryAssetLabel), set the Cook Rule to Always Cook, and enable Label Assets in My Directory. This labels every asset in that folder as a primary asset, guaranteeing the cooker includes them.

Reading the Cook Log

To confirm whether your widget was cooked, open the cook log during your next package. In the editor, go to Edit → Project Settings → Packaging and enable Create Compressed Cooked Packages with the log verbosity set high, or run the cooker from the command line:

UnrealEditor-Cmd.exe MyProject.uproject \
  -run=Cook -TargetPlatform=Windows \
  -map=/Game/Maps/MainMenu \
  -log -verbose

Search the output log (saved to Saved/Logs/) for your widget’s package path. A line like Display: Cooked /Game/UI/WBP_HUD confirms it was included. If you see Warning: Soft reference not followed or your widget simply doesn’t appear in the log at all, your reference chain is broken.

You can also inspect the cooked content directory directly. After packaging to WindowsNoEditor/, look inside WindowsNoEditor/MyProject/Content/. Your widget blueprint should appear as a .uasset file. If it’s absent, it was never cooked.

Soft References: What They Do and Don’t Guarantee

It’s worth understanding the hard/soft reference distinction precisely because it trips up even experienced Unreal developers.

A hard reference (UPROPERTY of type UObject*, TSubclassOf<T>, or TObjectPtr<T>) is serialized as a direct asset dependency. The cooker follows it automatically. The asset is loaded into memory when the outer object loads.

A soft reference (TSoftObjectPtr<T>, TSoftClassPtr<T>) stores the asset path as a string. The cooker does not automatically follow it unless the asset is registered in the AssetManager or reachable via some other hard reference. The asset is not loaded until you explicitly call LoadSynchronous() or use an async load request.

The practical rule: if a widget must always be available at runtime without an explicit load call, use a hard reference. If you’re building a system that loads widgets on demand (e.g., a level-specific tutorial overlay), use soft references plus AssetManager cook rules.

Related Issues

If the widget is cooked but still not visible, check these secondary causes:

Once you’ve fixed the reference chain and verified the cook log, the widget should appear in your very next packaged build — no code changes required, just the asset dependency wired correctly.