stride3d/stride · error · InvalidOperationException

An IObjectNode was expected when processing the path

Error message

An IObjectNode was expected when processing the path [{path}]

What it means

AssetPropertyGraph.ResolveObjectPath throws this InvalidOperationException while walking a YamlAssetPath: an element was resolved through a reference node, and the node reached is not an IObjectNode (it has no indexed children) even though more path elements follow. This signals the serialized path no longer matches the live node structure — typically a stale path after the object model changed.

Solutions

  1. Regenerate the asset path (re-diff or re-record the override) against the current object model
  2. Upgrade/fix the asset file so the stored path matches the current schema
  3. Validate the path node-by-node with TryGetNode-style lookups before applying, and skip/repair invalid paths
  4. Roll back the schema change that altered the referenced object's shape

Example fix

// before
var node = graph.ResolveObjectPath(path); // throws on stale path
// after
if (!graph.TryResolvePath(path, out var node)) { Console.Error.WriteLine($"Stale path {path}; re-recording override"); return; }
Defensive patterns

Strategy: validation

Validate before calling

bool pathLooksValid = path.Elements.All(el => el.Type switch {
    YamlAssetPath.ElementType.MemberId => true,
    _ => true }); // validate segment-by-segment against the live graph before applying

Type guard

bool isObjectNode = node is IObjectNode;

Try / catch

try { var node = graph.ResolveObjectPath(path); } catch (InvalidOperationException ex) when (ex.Message.Contains("IObjectNode was expected")) { // path is stale: re-diff or skip this override }

Prevention

When it happens

Trigger: Resolving a YamlAssetPath whose MemberId/Index element targets an IsReference node whose Target is not an IObjectNode; usually paths loaded from old YAML diffs, overridden-value paths, or paths constructed against a different object layout.

Common situations: Applying saved overrides/patches after the asset class schema changed (property turned from collection to reference or vice versa); version upgrades of the engine changing object shapes; hand-crafted paths in migration scripts.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

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

                        if (currentNode.IsReference)
                        {
                            if (currentNode is not IMemberNode memberNode) throw new InvalidOperationException($"An IMemberNode was expected when processing the path [{path}]");
                            currentNode = (IAssetNode?)memberNode.Target;
                        }
                        if (currentNode is not IObjectNode objectNode) throw new InvalidOperationException($"An IObjectNode was expected when processing the path [{path}]");
                        var name = item.AsMember();
                        currentNode = (IAssetNode?)objectNode.TryGetChild(name);
                        break;
                    }
                case YamlAssetPath.ElementType.Index:
                    {
                        index = new NodeIndex(item.Value);
                        resolveOnIndex = true;
                        if (currentNode is not IMemberNode memberNode) throw new InvalidOperationException($"An IMemberNode was expected when processing the path [{path}]");
                        currentNode = (IAssetNode?)memberNode.Target;
                        if (currentNode.IsReference && i < path.Elements.Count - 1)
                        {
                            if (currentNode is not IObjectNode objNode) throw new InvalidOperationException($"An IObjectNode was expected when processing the path [{path}]");
                            currentNode = (IAssetNode?)objNode.IndexedTarget(new NodeIndex(item.Value));
                        }
                        break;
                    }
                case YamlAssetPath.ElementType.ItemId:
                    {
                        var ids = CollectionItemIdHelper.GetCollectionItemIds(currentNode.Retrieve());
                        var key = ids.GetKey(item.AsItemId());
                        index = new NodeIndex(key);
                        resolveOnIndex = false;
                        if (currentNode is not IMemberNode memberNode) throw new InvalidOperationException($"An IMemberNode was expected when processing the path [{path}]");
                        currentNode = (IAssetNode?)memberNode.Target;
                        if (currentNode.IsReference && i < path.Elements.Count - 1)
                        {
                            if (currentNode is not IObjectNode objNode) throw new InvalidOperationException($"An IObjectNode was expected when processing the path [{path}]");
                            currentNode = (IAssetNode?)objNode.IndexedTarget(new NodeIndex(key));
                        }
                        break;

View on GitHub (pinned to 96fad776d2)