{"record":{"id":"d61e137cbf5df120","repo":"stride3d/stride","slug":"the-base-is-unset-for-the-current-node","errorCode":null,"errorMessage":"The base is unset for the current node.","messagePattern":"The base is unset for the current node\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/assets/Stride.Core.Assets.Quantum/AssetPropertyGraph.cs","lineNumber":720,"sourceCode":"\n    private void OnBaseContentChanged(INodeChangeEventArgs e, IGraphNode node)\n    {\n        var assetNode = (IAssetNode)node;\n\n        // Ignore base change if propagation is disabled.\n        if (!Container.PropagateChangesFromBase)\n            return;\n\n        if (node.IsReference && e.OldValue?.GetType().IsValueType == false)\n        {\n            var oldNode = (IAssetNode?)Container.NodeContainer.GetNode(e.OldValue);\n            UnlinkFromBase(oldNode);\n        }\n\n        UpdatingPropertyFromBase = true;\n        var baseNode = assetNode.BaseNode;\n        if (assetNode.BaseNode is null)\n            throw new InvalidOperationException(\"The base is unset for the current node.\");\n        RefreshBase(assetNode, (IAssetNode)baseNode);\n        ReconcileWithBase((IAssetNode)node);\n        UpdatingPropertyFromBase = false;\n\n        BaseContentChanged?.Invoke(e, node);\n    }\n\n    private void ReconcileWithBaseNode(IAssetNode assetNode, GraphNodePath currentPath, bool reconcileObjectReference, Dictionary<IGraphNode, NodeIndex>? nodesToReset)\n    {\n        var memberNode = assetNode as AssetMemberNode;\n        var objectNode = assetNode as IAssetObjectNodeInternal;\n        // Non-overridable members should not be reconciled.\n        if (assetNode?.BaseNode is null || memberNode?.CanOverride == false)\n            return;\n\n        var localValue = assetNode.Retrieve();\n        var baseValue = assetNode.BaseNode.Retrieve();\n","sourceCodeStart":702,"sourceCodeEnd":738,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/assets/Stride.Core.Assets.Quantum/AssetPropertyGraph.cs#L702-L738","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check assetNode.BaseNode != null before raising/processing the BaseNodeChanged event and skip reconciliation if unset","Unlink the node from its base before unsubscribing/triggering events in the correct order","Guard your own refresh logic so it does not fire base-change events after unlinking","Re-link the node to its base (re-apply the archetype) before reconciling"],"exampleFix":"// before\nOnBaseContentChanged(e, node); // may fire after unlink\n// after\nif (assetNode.BaseNode is null) return; // node already unlinked, nothing to reconcile\nOnBaseContentChanged(e, node);","handlingStrategy":"type-guard","validationCode":"if (assetNode.BaseNode is null)\n    return; // nothing to reconcile; skip raising/processing the base-change event","typeGuard":"bool hasBase = assetNode.BaseNode is not null;","tryCatchPattern":"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 }","preventionTips":["Unlink nodes from their base before tearing down event subscriptions","Avoid clearing archetype links concurrently with base content refresh","Check BaseNode for null before triggering reconciliation logic"],"tags":["dotnet","stride","quantum","assets"],"backgroundTag":"internal-invariant-violation","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}