{"record":{"id":"bcd64c01e2ad3bec","repo":"stride3d/stride","slug":"cannot-deserialize-collection-to-readonly-collection-type","errorCode":null,"errorMessage":"Cannot deserialize collection to readonly collection type [{thisObject.GetType()}].","messagePattern":"Cannot deserialize collection to readonly collection type \\[(.+?)\\]\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.Yaml/Serialization/Serializers/CollectionSerializer.cs","lineNumber":148,"sourceCode":"        /// <summary>\n        /// Reads the collection items.\n        /// </summary>\n        /// <param name=\"objectContext\">The object context.</param>\n        /// <exception cref=\"System.InvalidOperationException\">Cannot deserialize list to type [{0}]. No Add method found.DoFormat(thisObject.GetType())\n        /// or\n        /// Cannot deserialize list to readonly collection type [{0}]..DoFormat(thisObject.GetType())</exception>\n        protected virtual void ReadCollectionItems(ref ObjectContext objectContext)\n        {\n            var collectionDescriptor = (CollectionDescriptor) objectContext.Descriptor;\n            var thisObject = objectContext.Instance;\n\n            if (!collectionDescriptor.HasAdd)\n            {\n                throw new InvalidOperationException($\"Cannot deserialize collection to type [{thisObject.GetType()}]. No Add method found\");\n            }\n            if (collectionDescriptor.IsReadOnly(thisObject))\n            {\n                throw new InvalidOperationException($\"Cannot deserialize collection to readonly collection type [{thisObject.GetType()}].\");\n            }\n\n            // The collection may contain some initial data from its containing instance's ctor,\n            // let's replace the existing data with the data we have serialized\n            collectionDescriptor.Clear(thisObject);\n\n            var reader = objectContext.Reader;\n\n            var elementType = collectionDescriptor.ElementType;\n            var index = 0;\n            while (!reader.Accept<SequenceEnd>())\n            {\n                var currentDepth = objectContext.Reader.CurrentDepth;\n                var startParsingEvent = objectContext.Reader.Parser.Current;\n\n                try\n                {\n                    ReadAddCollectionItem(ref objectContext, elementType, collectionDescriptor, thisObject, index);","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.Yaml/Serialization/Serializers/CollectionSerializer.cs#L130-L166","documentation":"CollectionSerializer clears the target collection and re-adds deserialized items; if the collection instance reports itself read-only (CollectionDescriptor.IsReadOnly), items cannot be replaced, so this InvalidOperationException is thrown before reading items.","triggerScenarios":"Deserializing YAML into a collection instance that is read-only — e.g. property typed as IReadOnlyList<T>/IReadOnlyCollection<T>, an array-backed fixed collection, or a collection exposing IsReadOnly == true (Collection<T>.IsReadOnly, frozen collections).","commonSituations":"Using read-only collection interfaces as member types in YAML-serialized models; passing Array.AsReadOnly()/FrozenSet results into serialized object graphs; API changes where a property type became read-only.","solutions":["Change the member type to a writable collection (List<T>, T[], HashSet<T>, Dictionary<K,V>)","Initialize the member to a new mutable instance instead of a read-only wrapper","Add a DataContract/MemberWidth renaming or custom serializer for read-only collections","If the type is fixed, implement a custom serializer registered in the factory"],"exampleFix":"// before\npublic IReadOnlyList<int> Items { get; } = Array.AsReadOnly(new int[0]);\n// after\npublic List<int> Items { get; set; } = new List<int>();","handlingStrategy":"validation","validationCode":"var descriptor = TypeDescriptorFactory.Current.FindDescriptor(memberType) as CollectionDescriptor;\nif (descriptor?.IsReadOnly(instance) == true)\n    throw new InvalidOperationException($\"{memberType} is read-only; use a writable collection for deserialization\");","typeGuard":"static bool IsWritableCollection<T>(T c) where T: System.Collections.ICollection => !c.IsReadOnly;","tryCatchPattern":"try\n{\n    serializer.ReadYaml(ref objectContext);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"readonly collection\"))\n{\n    // re-initialize the member with a mutable instance and retry\n}","preventionTips":["Avoid IReadOnlyList/ReadOnlyCollection members in serialized object graphs","Initialize collection members with new List<T>() instead of read-only wrappers","Keep serialized model properties simple and mutable"],"tags":["yaml","deserialization","read-only","collection"],"backgroundTag":"unsupported-operation","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}