Description

Context

The LevelStreamingPersistence plugin can be used to remember and restore properties on actors and components that are part of a streamed level.

Blueprint variables can be marked as instance editable, meaning they can be modified by level designers on the map. If they aren’t instance editable, actor reconstruction logic assumes that they should be their default value.

Problem

When you use the persistence plugin to mark a blueprint variable as persisted, the persistence will silently fail in PIE. Restoring properties is applied in OnLevelBeginMakingInvisible, but during PIE actor construction scripts are rerun during IncrementalUpdateComponents, which happens after. Non-instance editable BP variables are reset to their default value.

Suggested Fix

Detect when a persisted variable is a blueprint variable and not instance editable. Then warn the user, via FMessageDialog, that it should be made instance editable. This could be detected:

  • At editor startup, if we would load property paths listed in the config file. It wouldn’t catch changes while editor is open.
  • Or at run-time when restoring the property, encapsulated with #if WITH_EDITOR to avoid a cost in packaged games.
Steps to Reproduce

In the attached repro project:

  • Open MAP_BadBPVar
  • Follow repro steps below. The repro blueprint is called BP_BaseTimerActor_BadVar.
  • In the native base class AExamplePersistentActor constructor, a memory address for the BP variable is resolved so you can set a data breakpoint on it.
    • I recommend streaming the level out, collecting garbage, then put a breakpoint on the constructor that triggers when the actor streams in.
    • Then on trigger, put a data breakpoint on the variable.
    • It first hits on LevelStreamingPersistenceManager
    • It then hits on RerunConstructionScripts

Blank project setup steps:

  • Enable LevelStreamingPersistence plugin
  • Create a blueprint BP_MyActor
    • Add a float variable to it, TimeAlive, leave it as not instance editable.
    • Increase TimeAlive on tick. Also print it on tick.
    • Add a cube mesh just to see the actor in the level.
  • Add to DefaultEngine.ini to persist the value:
[/Script/LevelStreamingPersistence.LevelStreamingPersistenceSettings]
+Properties=(Path="/Game/Blueprints/BP_MyActor.BP_MyActor_C:TimeAlive", bIsPublic=true)
  • Place BP_MyActor in the level. Leave it as spatially partitioned.
  • In World Settings, lower Cell Size and Loading Range to easily trigger level streaming in and out.

Repro steps:

  • Start PIE.
  • Move away to stream the level containing BP_MyActor out.
  • Call ‘obj gc’ to collect garbage, assuring that the level will be reloaded from disk
  • Move back to stream the level containing BP_MyActor in.
  • Observe: TimeAlive is reset to 0
  • Expected: TimeAlive is persisted
  • What happened:
    • The LevelStreamingPersistenceManager restores the value
    • But BP_MyActor’s RerunConstructionScripts will reset the value to 0
  • Go back to BP_MyActor
  • Make TimeAlive Instance Editable (press eye icon)
  • Repeat PIE steps. Observe that it works now.
Callstack

Non-fatal callstack. This is the callstack that stomps the restored persisted value in PIE when the BP variable is not marked instance editable:

>	UnrealEditor-Engine.dll!AActor::ResetPropertiesForConstruction() Line 110	C++
 	UnrealEditor-Engine.dll!AActor::RerunConstructionScripts() Line 589	C++
 	UnrealEditor-Engine.dll!ULevel::IncrementalRunConstructionScripts(bool bProcessAllActors) Line 2078	C++
 	UnrealEditor-Engine.dll!ULevel::IncrementalUpdateComponents(int NumComponentsToUpdate, bool bRerunConstructionScripts, FRegisterComponentContext * InContext) Line 1891	C++
 	UnrealEditor-Engine.dll!UWorld::AddToWorld(ULevel * Level, const UE::Math::TTransform<double> & LevelTransform, bool bConsiderTimeLimit, const TOptional<UE::FTimeout const> & ExternalTimeout, FNetLevelVisibilityTransactionId TransactionId, ULevelStreaming * InOwningLevelStreaming) Line 3792	C++
 	UnrealEditor-Engine.dll!ULevelStreaming::UpdateStreamingState(bool & bOutUpdateAgain, bool & bOutRedetermineTarget, const TOptional<UE::FTimeout const> & InExternalTimeout) Line 1059	C++
 	[Inline Frame] UnrealEditor-Engine.dll!FStreamingLevelPrivateAccessor::UpdateStreamingState(ULevelStreaming *) Line 808	C++
 	UnrealEditor-Engine.dll!UWorld::UpdateLevelStreaming(const TOptional<UE::FTimeout const> & ExternalTimeout) Line 5045	C++

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-368855 in the post.

0
Login to Vote

Fixed
ComponentUE - World Creation - Worldbuilding Tools
Affects Versions5.35.45.55.65.7
Target Fix5.8
Fix Commit52347206
CreatedMar 6, 2026
ResolvedApr 1, 2026
UpdatedMay 29, 2026
View Jira Issue