[StateTree]Linked Asset state parameter overrides revert to default values when the SubTree completes and re-enters in the same frame

When a Linked Asset state (StateA) in a MainTree links to a SubTree with overridden parameters, the parameter overrides are correctly applied on the first entry. However, if the SubTree completes (Tree Succeeded) and there is no completion transition defined on StateA, the engine falls back to Root and re-selects StateA in the same frame. On this re-entry, the parameter overrides are not applied — the SubTree receives default parameter values instead.

This issue exists in UE 5.7 (our base) and is still present in UE 5.8 preview.

Root Cause

In FStateTreeExecutionContext::SelectStateInternal (StateTreeExecutionContext.cpp), during the “Update state parameters” section:

// Instantiate temporary state parameters if not done yet.
FStateTreeDataView NextStateParametersView = GetDataViewOrTemporary(NextParentFrame, *NextFrame, NextState.ParameterDataHandle);
if (!NextStateParametersView.IsValid())
{
  // ... create temporary instance with override values ...
}

GetDataViewOrTemporary calls IsHandleSourceValid, which checks IsActiveInstanceHandleSourceValid. On re-entry within the same frame, the old state has not yet been removed from ActiveStates, and its instance data in storage is still valid. Therefore IsHandleSourceValid returns true, and GetDataViewOrTemporary returns the stale old data view. Because NextStateParametersView is valid, the temporary instance creation (which would apply the parameter override) is skipped entirely.Later in UpdateInstanceData, the state is correctly identified as non-common (new state due to CompletedTransitionStatesCreateNewStates

in default StateSelectionRules). It looks for temporary instance data via FindInstanceTempData

— but finds none (because it was never created). It then falls back to the SubTree’s GetDefaultParameters(), losing the override values.

Our Fix

We guard the GetDataViewOrTemporary call with bShouldCreateNewState. When the state is being recreated, we skip the lookup to ensure the temporary instance is always created with the correct override values:

// When creating a new state, skip GetDataViewOrTemporary which may return stale data from the
// still-active old instance, causing the temporary creation below to be skipped. Without a
// temporary, UpdateInstanceData falls back to the SubTree's default parameters.
FStateTreeDataView NextStateParametersView;
if (!bShouldCreateNewState)
{
  NextStateParametersView = GetDataViewOrTemporary(NextParentFrame, *NextFrame, NextState.ParameterDataHandle);
}
if (!NextStateParametersView.IsValid())
{
  // ... existing temporary creation logic (unchanged) ...
}
  1. Create SubTree (ST_Sub, Schema: StateTree AI Component), Add an int Parameter named TestValue, default = 0
  2. ST_Sub.Root has a Print String task that prints TestValue and finish task
  3. ST_Sub.Root has a transition: On State Completed → Tree Succeeded (completes immediately)
  4. Create MainTree (ST_Main, Schema: StateTree AI Component)
  5. ST_Main.Root has one child state LinkedState, type = Linked Asset, referencing ST_Sub
  6. Override TestValue parameter on LinkedState to 999
  7. Do NOT add any completion transition on LinkedState (forces engine fallback to Root)
  8. Create a Pawn BP + AI Controller with StateTreeAIComponent set to ST_Main
  9. Place the Pawn in a level and Play in Editor

Expected: Every entry prints 999

Actual: First entry prints 999, second and all subsequent entries print 0

This is indeed an unintended case. Looking over the code, it looks like a very good fix. I am waiting to talk about it some more with our StateTree owner as I know some other fixes have been in flight for updating parameters for sustained states. My initial testing does seem quite promising, but I want another set of eyes to make sure I didn’t overlook a possible edge case from the change.

-James