[UE 5.8.3][Editor] An actor with runtime-generated PCG output gains a None entry in InstanceComponents for every generated component each time its level is reopened and saved, without limit

Summary

An actor that hosts the output of a PCG component set to Generate At Runtime (not partitioned, for example a PCG Volume) collects null entries in its saved InstanceComponents array. Each reopen-and-save of the level adds one None per generated component, and nothing ever removes them. A stock PCG Volume spawning three meshes went from 3 to 6 to 9 None entries over three editor sessions, and the file grew by exactly 12 bytes per session (one 4-byte reference each). In our project, 36 such actors in one level had built up 22,163 of them, 3,719 on a single actor.

Cause, from reading the source: UPCGActorHelpers::GetOrCreateManagedISMC creates Preview-mode output with RF_Transient | RF_NonPIEDuplicateTransient and then calls AddInstanceComponent on the target actor (PCGActorHelpers.cpp:245; the same for instanced skinned meshes at 391 and spline meshes at 571). AActor::InstanceComponents is a saved UPROPERTY(Instanced), and a save cannot export a transient object, so each entry is written as a null reference. Nothing drops nulls on load: AActor::PostLoad and RerunConstructionScripts keep them. PCG’s own cleanup (DestroyComponent, then RemoveOwnedComponent) removes only live entries, so every new session’s output adds a fresh set.

Possible fixes (not tested): don’t add transient Preview output to InstanceComponents, since it is never saved anyway; or skip RF_Transient entries when saving InstanceComponents; or drop null entries in AActor::PostLoad.

What Type of Bug are you experiencing?

Editor

Steps to Reproduce

  1. Create a PCG graph: Create Points Grid (Grid Extents 500, 500, 0; Cell Size 200, 200, 100) into a Static Mesh Spawner with three entries, /Engine/BasicShapes/Cube, Sphere and Cylinder, weight 1 each.
  2. In an empty level, place a PCG Volume, scale it to 6, 6, 1, assign the graph, and set Generation Trigger to Generate At Runtime. Wait for the meshes to appear, then save the level.
  3. Close and reopen the level, wait for the meshes, and save. Do this twice.
  4. After each save, export the level to T3D and count the InstanceComponents(n)=None lines under the PCG Volume. We used an AssetExportTask on the saved world; File > Export All writes the same format.

Expected Result

The volume’s saved InstanceComponents stays empty: its generated components are transient and are never saved, so there is nothing to list.

Observed Result

  • The volume carries 3 generated components. The three saves hold 3, then 6, then 9 InstanceComponents(n)=None entries.
  • A second save in the same session writes a byte-identical file, so the growth needs a reopen.
  • The file grows by exactly 12 bytes per reopen-and-save (3 null references of 4 bytes each). Nothing else in it changes.

Measured with a T3D export of each saved package. Tested on UE 5.8.3 (CL 58210709, launcher build), macOS 27.0.1, Apple Silicon.

Affects Versions

5.8

Platform(s)

Mac

Additional Notes

Nothing breaks: the engine null-checks wherever it walks InstanceComponents. But the growth has no bound, and it reaches every actor that hosts its own runtime-generated PCG output. Copy, paste and duplicate carry the array as text, so a duplicate starts with its source’s None entries. From reading the source, the Details panel’s “Apply Instance Changes” and “Reset to Class Defaults” tooltips (SSubobjectInstanceEditor) add InstanceComponents.Num() to their changed-property count, so on such an actor they report thousands of changes.

Our level-design plugin’s room actors host their PCG output directly, which is how one level collected 22,163 entries. We now drop the nulls in PostLoad of our own actor class. That keeps each saved file to its last session’s entries.

Related: our earlier report on copy and paste of runtime-generated PCG output, [UE 5.8.3][Editor] Duplicating or copy-pasting an actor with runtime-generated PCG output saves that output into the copy, which then shows it twice when the level is reopened