Packaged build crashes when returning to a level with a UMG widget (UE 5.6.1)

Struggling for weeks now with this. Packaged build crashes reliably when the player returns to the main menu level, which builds and displays a UMG widget (created via Create Widget → Add to Viewport in BP_GameModeMainMenu’s BeginPlay).

The crash happens on the second Construct/paint pass of the widget. Meaning we can access the main menu widget once, no problem. But returning to the main menu at any later point produces the crash. This never happens in PIE, only packaged builds (DebugGame & Development).

Crash: Assertion failed: Index >= 0 [UObjectArray.h, Line: 1037], inside FSlateClippingZone::IsPointInside called from SGameLayerManager::OnPaint, ultimately from FSlateInvalidationRoot::PaintInvalidationRoot.

What I’ve ruled out through isolation testing:

  • Widget content: stripped the widget down to a single empty Canvas Panel — still crashes.
  • The specific widget asset: replaced it with an unrelated Widget Blueprint — still crashes.
  • No widget at all: removed Create Widget/Add to Viewport entirely — crash stops completely.
  • GC-unsafe reference: ensured the created widget was stored in a Blueprint variable reference on BP_GameModeMainMenu — still crashes.
  • Explicit teardown: added Remove From Parent on the stored widget reference right before level change — still crashes.
  • Slate’s global invalidation cache: set Slate.EnableGlobalInvalidation=0 via DefaultEngine.ini [ConsoleVariables] — confirmed active in the log, still crashes.

Any pointers on what else to check would be hugely appreciated.

the stack points at slate painting a widget whose underlying umg object is gone, so this is almost certainly a stale widget reference surviving the level transition, not a paint bug. the first menu works, the second construction crashes, which fits a pointer kept from the first pass.

work through this checklist:

  1. whoever holds the first menu widget (game instance, subsystem, a static, the player controller) is keeping it alive across the travel. widgets should live and die with the level. search for where the widget variable is stored and make sure it is cleared. a reference held anywhere outside the level also blocks gc, which produces exactly this assert when slate later walks freed objects.
  2. before opening the level, remove from parent on the widget and reset input mode: set input mode game only, then open level. set input mode ui or ui and game keeps an slategasreference to your widget in the input stack, and that is a classic source of onpaint asserts after travel.
  3. if the return to menu uses open level nodes, try seamless travel off (travel to url with absolute false and seamless false) to rule out the streaming path keeping the old viewport layer alive mid transition.
  4. in the crash the assert is index based inside clipping, so also check you are not adding the widget to viewport twice (beginplay firing again on return while the old one is still parented). a quick log in beginplay of the game mode counting constructions will show it.
  5. as an experiment, disable tick on the menu widget and any atlas based clipping (set clipping to inherit rather than clip to bounds) to confirm the clipping zone path is the only crash site.
    if after step 1 and 2 it still asserts, the last thing to look at is the game layer manager holding a viewport client from the previous world, which happens when something calls add to viewport during world teardown. guard the add to viewport with a validity check on is valid and delay one frame after beginplay on the return path.

Thanks for the help! After many more hours of trial and error, I found it was something else entirely. In the gameplay’s game mode class (not the main menu game mode), I had been overriding SetFocusBrush in c++, then setting a new brush in BeginPlay.

// Overrides the Focus brush in the FStarshipCoreStyle.
UFUNCTION(BlueprintCallable, Category = "Mythic UI Manager | Slate Overrides")
void SetFocusBrush(FSlateBrush InBrush) {
    OverridenFocusBrush = InBrush;
    FStarshipCoreStyle::SetFocusBrush(&OverridenFocusBrush);
}

Not sure why, but removing the SetFocusBrush call from within BeginPlay fixed the issue. No more crashes! I could probably make SetFocusBrush work reliably, but seems better to highlight buttons etc. with events like On Added To Focus Path & On Removed From Focus Path.