stride3d/stride · error · InvalidOperationException
Unable to find the graph corresponding to the base part
Error message
Unable to find the graph corresponding to the base part
What it means
In AssetCompositeHierarchyPropertyGraph's base-asset change handler, this InvalidOperationException is thrown when Container.TryGetGraph(baseAsset.Id) does not return an AssetCompositeHierarchyPropertyGraph<TAssetPartDesign,TAssetPart>. A part changed in the base asset, but its graph is missing or not a hierarchy graph, so instance parts cannot be propagated. It enforces the invariant that a hierarchy base asset always has a matching hierarchy graph in the container.
Solutions
- Load/restore the base composite asset so its hierarchy graph is registered in the container
- Re-save or recreate the derived asset with a valid base reference
- Rebuild the asset database/package to re-register missing graphs
- Remove the base linkage from the derived asset if inheritance is no longer wanted
Example fix
// before
var graph = container.TryGetGraph(baseAssetId); // may be null / wrong type
// after
var graph = container.TryGetGraph(baseAssetId);
if (graph is null) { Console.Error.WriteLine($"Base asset {baseAssetId} not loaded; skipping propagation"); return; } Defensive patterns
Strategy: try-catch
Validate before calling
var graph = Container.TryGetGraph(baseAsset.Id); bool canPropagate = graph is AssetCompositeHierarchyPropertyGraph<TAssetPartDesign, TAssetPart>;
Type guard
if (Container.TryGetGraph(baseAsset.Id) is AssetCompositeHierarchyPropertyGraph<TAssetPartDesign, TAssetPart> baseGraph) { /* safe to propagate */ } Try / catch
try { HandleBaseChanged(e); } catch (InvalidOperationException ex) when (ex.Message.Contains("graph corresponding to the base part")) { // reload base asset or remove derived asset's base link } Prevention
- Keep base composite assets loaded in the same container as derived assets
- Do not change an asset's type after other assets derive from it
- Rebuild the asset database after manual asset-file edits
When it happens
Trigger: Receiving a BaseAssetChanged event whose base asset Id has no graph registered in the container, or whose graph is a different graph type (e.g. a plain AssetPropertyGraph rather than a hierarchy graph).
Common situations: Base composite assets (prefab/scene-like assets) deleted or unloaded while derived assets remain; type mismatches after changing an asset's type; partial package loads; corrupted or hand-edited asset files with stale base references.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Unable to find the base [{AssetItem.Asset.Archetype.Location
- The base is unset for the current node.
- An IObjectNode was expected when processing the path [{path}
- An IMemberNode was expected when processing the path [{path}
- No Collection item identifier associated to the given collec
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/6598030344d023f8.
Report an issue: GitHub.
Appendix: source
Thrown at sources/assets/Stride.Core.Assets.Quantum/AssetCompositeHierarchyPropertyGraph.cs:681
}
}
// Register to new base part events
foreach (var basePartAsset in newBasePartAsset)
{
basePartAsset.PartAdded += PartAddedInBaseAsset;
basePartAsset.PartRemoved += PartRemovedInBaseAsset;
}
}
private void PartAddedInBaseAsset(object? sender, AssetPartChangeEventArgs e)
{
UpdatingPropertyFromBase = true;
var baseAsset = (AssetCompositeHierarchy<TAssetPartDesign, TAssetPart>)e.Asset;
var newPart = baseAsset.Hierarchy.Parts[e.PartId];
var newPartParent = baseAsset.GetParent(newPart.Part);
if (Container.TryGetGraph(baseAsset.Id) is not AssetCompositeHierarchyPropertyGraph<TAssetPartDesign, TAssetPart> baseAssetGraph) throw new InvalidOperationException("Unable to find the graph corresponding to the base part");
foreach (var instanceId in basePartAssets[baseAssetGraph])
{
// Discard the part if this asset don't want it
if (!ShouldAddNewPartFromBase(baseAssetGraph, newPart, newPartParent, instanceId))
continue;
var insertIndex = FindBestInsertIndex(baseAsset, newPart, newPartParent, instanceId, out var instanceParent);
if (insertIndex < 0)
continue;
// Now we know where to insert, let's clone the new part.
const SubHierarchyCloneFlags flags = SubHierarchyCloneFlags.GenerateNewIdsForIdentifiableObjects | SubHierarchyCloneFlags.RemoveOverrides;
var baseHierarchy = CloneSubHierarchies(baseAssetGraph.Container.NodeContainer, baseAssetGraph.Asset, newPart.Part.Id.Yield(), flags, out Dictionary<Guid, Guid> mapping);
foreach (var ids in mapping)
{
// Process only ids that correspond to parts
if (!baseHierarchy.Parts.TryGetValue(ids.Value, out var clone))View on GitHub (pinned to 96fad776d2)