stride3d/stride · error · InvalidOperationException

The base is unset for the current node.

Error message

The base is unset for the current node.

What it means

In AssetPropertyGraph's base-node change handling, this InvalidOperationException is thrown when assetNode.BaseNode is null at the moment a BaseNodeChanged event is processed. The handler must reconcile the node with its base, but there is no base node — meaning the node was unlinked from its base while the change event was still being processed, or base linking state is inconsistent. It enforces the internal invariant that this event handler only runs for nodes that actually have a base.

Solutions

  1. Check assetNode.BaseNode != null before raising/processing the BaseNodeChanged event and skip reconciliation if unset
  2. Unlink the node from its base before unsubscribing/triggering events in the correct order
  3. Guard your own refresh logic so it does not fire base-change events after unlinking
  4. Re-link the node to its base (re-apply the archetype) before reconciling

Example fix

// before
OnBaseContentChanged(e, node); // may fire after unlink
// after
if (assetNode.BaseNode is null) return; // node already unlinked, nothing to reconcile
OnBaseContentChanged(e, node);
Defensive patterns

Strategy: type-guard

Validate before calling

if (assetNode.BaseNode is null)
    return; // nothing to reconcile; skip raising/processing the base-change event

Type guard

bool hasBase = assetNode.BaseNode is not null;

Try / catch

try { ReconcileNode(assetNode); } catch (InvalidOperationException ex) when (ex.Message == "The base is unset for the current node.") { // node was unlinked: skip reconciliation or re-link first }

Prevention

When it happens

Trigger: Raising/processing a BaseNodeChanged event for a node whose base link was just cleared (UnlinkFromBase), or whose asset never had a base linked; concurrent unlinking while base content changes propagate.

Common situations: Clearing an archetype/base link while base refresh is in flight; programmatic manipulation of Quantum graphs that unlinks nodes without cancelling event subscriptions; race conditions during editor shutdown or asset reload.

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


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/d61e137cbf5df120. Report an issue: GitHub.

Appendix: source

Thrown at sources/assets/Stride.Core.Assets.Quantum/AssetPropertyGraph.cs:720

    private void OnBaseContentChanged(INodeChangeEventArgs e, IGraphNode node)
    {
        var assetNode = (IAssetNode)node;

        // Ignore base change if propagation is disabled.
        if (!Container.PropagateChangesFromBase)
            return;

        if (node.IsReference && e.OldValue?.GetType().IsValueType == false)
        {
            var oldNode = (IAssetNode?)Container.NodeContainer.GetNode(e.OldValue);
            UnlinkFromBase(oldNode);
        }

        UpdatingPropertyFromBase = true;
        var baseNode = assetNode.BaseNode;
        if (assetNode.BaseNode is null)
            throw new InvalidOperationException("The base is unset for the current node.");
        RefreshBase(assetNode, (IAssetNode)baseNode);
        ReconcileWithBase((IAssetNode)node);
        UpdatingPropertyFromBase = false;

        BaseContentChanged?.Invoke(e, node);
    }

    private void ReconcileWithBaseNode(IAssetNode assetNode, GraphNodePath currentPath, bool reconcileObjectReference, Dictionary<IGraphNode, NodeIndex>? nodesToReset)
    {
        var memberNode = assetNode as AssetMemberNode;
        var objectNode = assetNode as IAssetObjectNodeInternal;
        // Non-overridable members should not be reconciled.
        if (assetNode?.BaseNode is null || memberNode?.CanOverride == false)
            return;

        var localValue = assetNode.Retrieve();
        var baseValue = assetNode.BaseNode.Retrieve();

View on GitHub (pinned to 96fad776d2)