{"record":{"id":"c716e315c581ee9c","repo":"stride3d/stride","slug":"an-iobjectnode-was-expected-when-processing-the-path-path","errorCode":null,"errorMessage":"An IObjectNode was expected when processing the path [{path}]","messagePattern":"An IObjectNode was expected when processing the path \\[(.+?)\\]","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/assets/Stride.Core.Assets.Quantum/AssetPropertyGraph.cs","lineNumber":360,"sourceCode":"                        if (currentNode.IsReference)\n                        {\n                            if (currentNode is not IMemberNode memberNode) throw new InvalidOperationException($\"An IMemberNode was expected when processing the path [{path}]\");\n                            currentNode = (IAssetNode?)memberNode.Target;\n                        }\n                        if (currentNode is not IObjectNode objectNode) throw new InvalidOperationException($\"An IObjectNode was expected when processing the path [{path}]\");\n                        var name = item.AsMember();\n                        currentNode = (IAssetNode?)objectNode.TryGetChild(name);\n                        break;\n                    }\n                case YamlAssetPath.ElementType.Index:\n                    {\n                        index = new NodeIndex(item.Value);\n                        resolveOnIndex = true;\n                        if (currentNode is not IMemberNode memberNode) throw new InvalidOperationException($\"An IMemberNode was expected when processing the path [{path}]\");\n                        currentNode = (IAssetNode?)memberNode.Target;\n                        if (currentNode.IsReference && i < path.Elements.Count - 1)\n                        {\n                            if (currentNode is not IObjectNode objNode) throw new InvalidOperationException($\"An IObjectNode was expected when processing the path [{path}]\");\n                            currentNode = (IAssetNode?)objNode.IndexedTarget(new NodeIndex(item.Value));\n                        }\n                        break;\n                    }\n                case YamlAssetPath.ElementType.ItemId:\n                    {\n                        var ids = CollectionItemIdHelper.GetCollectionItemIds(currentNode.Retrieve());\n                        var key = ids.GetKey(item.AsItemId());\n                        index = new NodeIndex(key);\n                        resolveOnIndex = false;\n                        if (currentNode is not IMemberNode memberNode) throw new InvalidOperationException($\"An IMemberNode was expected when processing the path [{path}]\");\n                        currentNode = (IAssetNode?)memberNode.Target;\n                        if (currentNode.IsReference && i < path.Elements.Count - 1)\n                        {\n                            if (currentNode is not IObjectNode objNode) throw new InvalidOperationException($\"An IObjectNode was expected when processing the path [{path}]\");\n                            currentNode = (IAssetNode?)objNode.IndexedTarget(new NodeIndex(key));\n                        }\n                        break;","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/assets/Stride.Core.Assets.Quantum/AssetPropertyGraph.cs#L342-L378","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Regenerate the asset path (re-diff or re-record the override) against the current object model","Upgrade/fix the asset file so the stored path matches the current schema","Validate the path node-by-node with TryGetNode-style lookups before applying, and skip/repair invalid paths","Roll back the schema change that altered the referenced object's shape"],"exampleFix":"// before\nvar node = graph.ResolveObjectPath(path); // throws on stale path\n// after\nif (!graph.TryResolvePath(path, out var node)) { Console.Error.WriteLine($\"Stale path {path}; re-recording override\"); return; }","handlingStrategy":"validation","validationCode":"bool pathLooksValid = path.Elements.All(el => el.Type switch {\n    YamlAssetPath.ElementType.MemberId => true,\n    _ => true }); // validate segment-by-segment against the live graph before applying","typeGuard":"bool isObjectNode = node is IObjectNode;","tryCatchPattern":"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 }","preventionTips":["Re-record saved overrides after upgrading the engine or changing asset schemas","Do not hand-edit YAML paths in asset files","Version-check stored diffs before applying them"],"tags":["dotnet","stride","yaml","quantum"],"backgroundTag":"type-mismatch","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"}