{"record":{"id":"722cafc3759ffd8d","repo":"stride3d/stride","slug":"value-type-for-root-objects-are-not-supported","errorCode":null,"errorMessage":"Value type for root objects are not supported","messagePattern":"Value type for root objects are not supported","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.Reflection/MemberPath.cs","lineNumber":223,"sourceCode":"        ArgumentNullException.ThrowIfNull(descriptor);\n        AddItem(new SetPathItem(descriptor, index));\n    }\n\n    /// <summary>\n    /// Pops the last item from the current path.\n    /// </summary>\n    public void Pop()\n    {\n        if (items.Count > 0)\n        {\n            items.RemoveAt(items.Count - 1);\n        }\n    }\n\n    public bool Apply(object rootObject, MemberPathAction actionType, object? value)\n    {\n        ArgumentNullException.ThrowIfNull(rootObject);\n        if (rootObject.GetType().IsValueType) throw new ArgumentException(\"Value type for root objects are not supported\", nameof(rootObject));\n        if (actionType != MemberPathAction.ValueSet && actionType != MemberPathAction.CollectionAdd && value != null)\n        {\n            throw new ArgumentException(\"Value must be null for action != (MemberActionType.SetValue || MemberPathAction.CollectionAdd)\");\n        }\n\n        if (items == null || items.Count == 0)\n        {\n            throw new InvalidOperationException(\"This instance doesn't contain any path. Use Push() methods to populate paths\");\n        }\n\n        var lastItem = items[^1];\n        switch (actionType)\n        {\n            case MemberPathAction.CollectionAdd:\n                if (lastItem is not CollectionPathItem)\n                {\n                    throw new ArgumentException(\"Invalid path [{0}] for action [{1}]. Expecting last path to be a collection item\".ToFormat(this, actionType));\n                }","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.Reflection/MemberPath.cs#L205-L241","documentation":"MemberPath.Apply performs a get/set action along a member path starting from a root object. Value-type roots are rejected with ArgumentException because the path mutations would operate on a boxed copy and be lost; only reference-type roots are supported.","triggerScenarios":"Calling Apply with a struct instance (e.g. a Vector3, or a struct wrapping data) as rootObject.","commonSituations":"Using MemberPath on struct-based data models or components that are structs; passing a struct after deserialization; test code (e.g. TestMyClass) exercising paths against value-type fixtures.","solutions":["Box the value into a class or use a class wrapper as the root before applying the path","Operate on a field/property of a class that holds the struct instead of the struct itself","Refactor the root data type to be a reference type"],"exampleFix":"// before\nvar path = new MemberPath(...);\npath.Apply(myStruct, MemberPathAction.ValueSet, value);\n// after\nclass Root { public MyStruct Data; }\npath.Apply(root, MemberPathAction.ValueSet, value); // root is a class","handlingStrategy":"validation","validationCode":"if (rootObject.GetType().IsValueType) throw new ArgumentException(\"MemberPath.Apply requires a reference-type root\");","typeGuard":"bool canApply = !rootObject.GetType().IsValueType;","tryCatchPattern":"try { path.Apply(root, action, value); }\ncatch (ArgumentException) { /* root was a struct; wrap in a class */ }","preventionTips":["Use class roots for MemberPath operations","Store structs as members of a class and path through the class","Validate root type in helper wrappers"],"tags":["csharp","reflection","value-types","argument"],"backgroundTag":"invalid-argument-value","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"}