A scan over a few existing assets shows a large number of orphaned nodes and duplicate node GUIDs. Before we go ahead and fix those we want to check in and ask the experts if our reasoning is sound, and if the engine can avoid similar issues going forward.
Orphaned Graph Nodes:
UEdGraph::RemoveNode removes nodes from the graph’s Nodes TArray but does not destroy the UObject or move it to the transient package. The node UObject remains in the Blueprint’s outer chain indefinitely. For standard UBlueprint assets, the Kismet compiler moves stale generated classes and CDOs to GetTransientPackage() during recompilation (KismetCompiler.cpp:634, KismetCompilerMisc.cpp:531), but this cleanup does not extend to orphaned UEdGraphNode subobjects. Non-compilable Blueprint-derived assets (Behavior Tree tasks/decorators/services, EQS contexts, etc.) never get this cleanup at all. Over time, undo/redo operations, node deletions, and graph restructuring accumulate orphaned node UObjects that are serialized into the .uasset but referenced by no graph. In our project, a scan of 80 Blueprints in a single AI folder found 7,923 orphaned nodes across 74 assets, with the worst offender containing 1,851 orphans.Those orphan nodes also pulls in unneeded dependencies, slowing down Editor startup times.
Duplicate Node GUIDs:
UEdGraphNode::NodeGuid is documented as a unique identifier to “facilitate diffing versions of this graph.” GUIDs are generated via FGuid::NewGuid() on construction and should be globally unique. However, certain editor operations (copy-paste across graphs, duplication edge cases) can produce nodes with identical GUIDs in different graphs within the same Blueprint. This violates the uniqueness assumption relied on by the Blueprint diff tool and Find-in-Blueprints indexing. In our scan, 2 of 80 Blueprints had duplicate GUIDs (11 total collisions), concentrated in assets with complex multi-graph structures.
[Attachment Removed]
Steps to Reproduce
The following pseudocode demonstrates detection without requiring specific project assets — any Blueprint with undo/redo history or deleted nodes can exhibit orphans:
// Load any Blueprint asset
UBlueprint* BP = LoadObject<UBlueprint>(nullptr, TEXT("/Game/Path/To/AnyBlueprint"));
// --- Orphan Detection ---
// Step 1: Collect all nodes that are referenced by a graph
TSet<UEdGraphNode*> LiveNodes;
TArray<UEdGraph*> AllGraphs;
BP->GetAllGraphs(AllGraphs);
for (UEdGraph* Graph : AllGraphs)
{
for (UEdGraphNode* Node : Graph->Nodes)
{
LiveNodes.Add(Node);
}
}
// Step 2: Find all UEdGraphNode UObjects in the package outer chain
TArray<UObject*> AllSubObjects;
GetObjectsWithOuter(BP, AllSubObjects, /*bIncludeNestedObjects=*/ true);
int32 OrphanCount = 0;
for (UObject* Obj : AllSubObjects)
{
UEdGraphNode* NodeObj = Cast<UEdGraphNode>(Obj);
if (NodeObj && !LiveNodes.Contains(NodeObj))
{
OrphanCount++;
// NodeObj is an orphan — exists in package but no graph references it
}
}
UE_LOG(LogTemp, Warning, TEXT("Found %d orphaned nodes in %s"), OrphanCount, *BP->GetName());
// --- Duplicate GUID Detection ---
TMap<FGuid, UEdGraphNode*> SeenGUIDs;
int32 DuplicateCount = 0;
for (UEdGraph* Graph : AllGraphs)
{
for (UEdGraphNode* Node : Graph->Nodes)
{
if (Node->NodeGuid.IsValid() && SeenGUIDs.Contains(Node->NodeGuid))
{
DuplicateCount++;
// Two live nodes share the same NodeGuid
}
else
{
SeenGUIDs.Add(Node->NodeGuid, Node);
}
}
}
UE_LOG(LogTemp, Warning, TEXT("Found %d duplicate GUIDs in %s"), DuplicateCount, *BP->GetName());
[Attachment Removed]
Hi Christian,
Thank you for the report and validation code you provided. I’ve been trying to reproduce the issues you described, but unfortunately I haven’t been successful so far. I implemented your code on a Validator for blueprint assets, and this is what I’m seeing:
- When I delete a node from a blueprint graph, it does get detected as “orphaned” by your test, but this is not unexpected since the node is still referenced by the transaction buffer for the undo system. If I then perform an undo of the operation or if I clear the undo history and recompile the blueprint, the node gets fully deleted. Also, if I save and reload the asset after deleting a node, it also gets fully deleted (the undo is invalidated by the reload).
- For blueprint assets that haven’t been fully loaded yet, it seems that every blueprint node has an “orphaned” duplicate which has the same GUID and is referenced by an internal graph. Nodes from the Event Graph are referenced by a graph named “ExecuteUbergraph_<ASSETNAME>”, while nodes from Function Graphs are referenced by a graph named “<FUNCTIONNAME>_MERGED”. All of these nodes go away once the asset is reloaded or once the blueprint editor is opened and closed for them.
- Event entrypoint nodes in general are also detected as “orphaned”, but even though they are not referenced by the graphs returned by GetAllGraphs(), they are also still referenced internally elsewhere.
- Regarding node with duplicate GUIDs: apart from those mentioned above which don’t seem to be a problem, I was not able to observe that behavior when duplicating or copy-pasting nodes across graphs.
Would you be able to provide detailed repro steps that result in the creation of persistent leaked graph nodes, and graph nodes with duplicate GUIDs? This would be very helpful for us to determine what exactly might be happening, and the most appropriate way to address these issues.
Best regards,
Vitor
[Attachment Removed]
Thank you for this information. We updated our test to avoid those false positives, and are now seeing significantly less orphans and duplicates: Across 80 example files we now have 2 orphans and 11 dupes, where we previously had almost 8k orphans.
Unfortunately we do not have a repro for how either of those were introduced, other than speculating about editor crashes or saving blueprints that don’t compile. However we’ll keep an eye on it!
[Attachment Removed]
Good to hear that most of the issues you detected were of the kinds that I mentioned. I’ll also try to keep an eye on this using the validator I implemented, but if you think you might have a good lead regarding how to repro the introduction of the orphans and dupes, feel free to post here (or on a new thread if this one gets closed), and we’ll follow up from there!
All the best,
Vitor
[Attachment Removed]