{"record":{"id":"e191db8d0b61fa73","repo":"stride3d/stride","slug":"shouldn-t-call-visitcollection-to-visit-a-set","errorCode":null,"errorMessage":"Shouldn't call VisitCollection() to visit a set","messagePattern":"Shouldn't call VisitCollection\\(\\) to visit a set","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.Design/Reflection/DataVisitorBase.cs","lineNumber":235,"sourceCode":"            var value = array.GetValue(i);\n            CurrentPath.Push(descriptor, i);\n            VisitArrayItem(array, descriptor, i, value, TypeDescriptorFactory.Find(value?.GetType() ?? descriptor.ElementType));\n            CurrentPath.Pop();\n        }\n    }\n\n    /// <inheritdoc />\n    public virtual void VisitArrayItem(Array array, ArrayDescriptor descriptor, int index, object? item, ITypeDescriptor? itemDescriptor)\n    {\n        Visit(item, itemDescriptor);\n    }\n\n    /// <inheritdoc />\n    public virtual void VisitCollection(IEnumerable collection, CollectionDescriptor descriptor)\n    {\n        if (descriptor.Category == DescriptorCategory.Set)\n        {\n            throw new ArgumentException(\"Shouldn't call VisitCollection() to visit a set\");\n        }\n        var i = 0;\n\n        // Make a copy in case VisitCollectionItem mutates something\n        foreach (var item in collection.Cast<object>().ToList())\n        {\n            CurrentPath.Push(descriptor, i);\n            VisitCollectionItem(collection, descriptor, i, item, TypeDescriptorFactory.Find(item?.GetType() ?? descriptor.ElementType));\n            CurrentPath.Pop();\n            i++;\n        }\n    }\n\n    /// <inheritdoc />\n    public virtual void VisitCollectionItem(IEnumerable collection, CollectionDescriptor descriptor, int index, object? item, ITypeDescriptor? itemDescriptor)\n    {\n        Visit(item, itemDescriptor);\n    }","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.Design/Reflection/DataVisitorBase.cs#L217-L253","documentation":"DataVisitorBase.VisitCollection() is the generic visitor entry point for enumerable collections, but sets (ISet implementations) are described by a SetDescriptor with a different category and must be visited through VisitSet()/VisitCollectionItem semantics instead. The library throws ArgumentException to stop the traversal before it treats set members like ordinary list items, which would produce incorrect visit results.","triggerScenarios":"Calling visitor.VisitCollection(collection, descriptor) where descriptor.Category == DescriptorCategory.Set, e.g. visiting an object graph that contains HashSet<T>/ISet<T> members via the generic collection path (as dispatched from VisitObject).","commonSituations":"Custom reflection-based property walkers or serializers built on DataVisitor that did not override/dispatch the set case; adding a new set-typed property to an object that is being visited; upgrading Stride and reusing an old visitor that predates the set category distinction.","solutions":["Override or extend the visitor so set-category descriptors are routed to the set visiting path (e.g. VisitSet) instead of VisitCollection","Check descriptor.Category == DescriptorCategory.Set before calling VisitCollection and handle it explicitly","If the collection is not semantically a set in your domain, change the property type to a List<T>/array so it maps to a non-set CollectionDescriptor"],"exampleFix":"// before\nvisitor.VisitCollection(value, descriptor);\n// after\nif (descriptor.Category == DescriptorCategory.Set)\n    VisitSet(value, descriptor);\nelse\n    visitor.VisitCollection(value, descriptor);","handlingStrategy":"validation","validationCode":"if (descriptor.Category == DescriptorCategory.Set)\n    throw new InvalidOperationException(\"Route sets to the set-visiting path, not VisitCollection\");","typeGuard":"bool IsSetDescriptor(CollectionDescriptor d) => d.Category == DescriptorCategory.Set;","tryCatchPattern":null,"preventionTips":["Always branch on descriptor.Category before dispatching collection visits","Cover set-typed members (HashSet<T>) in visitor unit tests","Derive custom visitors from DataVisitorBase and override the set path explicitly"],"tags":["reflection","visitor-pattern","argument-exception"],"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"}