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

ConvertPath walks a GraphNodePath step by step over the asset's node graph. For a Member step it must descend from an object node into a named child; if the current node is not an IObjectNode (e.g. it's an IMemberNode or primitive), the path is inconsistent with the graph and it throws.

Solutions

  1. Regenerate the GraphNodePath from the current asset graph rather than reusing persisted/serialized paths.
  2. Validate each step: before pushing a member, check currentNode is IObjectNode and TryGetChild(member) is non-null.
  3. Update the path after type/refactor changes to assets (member renamed or made scalar).
  4. Guard the caller with a check that the member exists on the node before converting the path.

Example fix

// before
result.PushMember(member); // assumes object node
// after
if (currentNode is IObjectNode objectNode && objectNode.TryGetChild(member) != null)
    result.PushMember(member);
else
    return null; // path no longer matches graph
Defensive patterns

Strategy: type-guard

Validate before calling

if (path.Path.Any(s => s.Type == GraphNodePath.ElementType.Member))
    rebuilt = AssetNodeMetadataCollectorBase.RebuildFromGraph(asset); // prefer regenerated paths

Type guard

static bool CanPushMember(IGraphNode n) => n is IObjectNode;

Try / catch

try { result = collector.ConvertPath(path); }
catch (InvalidOperationException) { result = null; // stale path }

Prevention

When it happens

Trigger: ConvertPath is given a path whose Member element expects the previous/current node to be an IObjectNode, but the node at that position is a member node, target, or scalar — typically a malformed or stale GraphNodePath whose structure doesn't match the actual asset graph.

Common situations: Path built against an older asset version whose type was refactored (member moved/renamed into a scalar); a path targeting a member of an object-reference rather than an object node; corrupted override paths in serialized asset metadata.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

Thrown at sources/assets/Stride.Core.Assets.Quantum/Visitors/AssetNodeMetadataCollectorBase.cs:79

    /// </summary>
    /// <param name="path">The path to convert.</param>
    /// <param name="inNonIdentifiableType">If greater than zero, will ignore collection item ids and write indices instead.</param>
    /// <returns>An instance of <see cref="YamlAssetPath"/> corresponding to the given <paramref name="path"/>.</returns>
    public static YamlAssetPath ConvertPath(GraphNodePath path, int inNonIdentifiableType = 0)
    {
        ArgumentNullException.ThrowIfNull(path);
        var currentNode = (IAssetNode)path.RootNode;
        var result = new YamlAssetPath();
        var i = 0;
        foreach (var item in path.Path)
        {
            switch (item.Type)
            {
                case GraphNodePath.ElementType.Member:
                {
                    var member = item.Name;
                    result.PushMember(member);
                        if (currentNode is not IObjectNode objectNode) throw new InvalidOperationException($"An IObjectNode was expected when processing the path [{path}]");
                        currentNode = (IAssetNode?)objectNode.TryGetChild(member);
                    break;
                }
                case GraphNodePath.ElementType.Target:
                {
                    if (i < path.Path.Count - 1)
                    {
                            if (currentNode is not IMemberNode targetingMemberNode) throw new InvalidOperationException($"An IMemberNode was expected when processing the path [{path}]");
                            currentNode = (IAssetNode?)targetingMemberNode.Target;
                    }
                    break;
                }
                case GraphNodePath.ElementType.Index:
                {
                    var index = item.Index;
                        if (currentNode is not AssetObjectNode objectNode) throw new InvalidOperationException($"An IObjectNode was expected when processing the path [{path}]");
                        if (inNonIdentifiableType > 0 || !CollectionItemIdHelper.HasCollectionItemIds(objectNode.Retrieve()))
                    {

View on GitHub (pinned to 96fad776d2)