{"record":{"id":"c0d15d396b595adb","repo":"OrchardCMS/OrchardCore","slug":"alternatecollection-can-t-be-changed","errorCode":null,"errorMessage":"AlternateCollection can't be changed.","messagePattern":"AlternateCollection can't be changed\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore/OrchardCore.DisplayManagement/Shapes/AlternatesCollection.cs","lineNumber":105,"sourceCode":"    }\n\n    public void AddRange(IEnumerable<string> alternates)\n    {\n        ArgumentNullException.ThrowIfNull(alternates);\n\n        EnsureMutable();\n\n        foreach (var alternate in alternates)\n        {\n            Add(alternate);\n        }\n    }\n\n    private void EnsureMutable()\n    {\n        if (this == Empty)\n        {\n            throw new NotSupportedException(\"AlternateCollection can't be changed.\");\n        }\n    }\n\n    public IEnumerator<string> GetEnumerator()\n        => _items.Values.GetEnumerator();\n\n    IEnumerator IEnumerable.GetEnumerator()\n        => _items.Values.GetEnumerator();\n}\n","sourceCodeStart":87,"sourceCodeEnd":115,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore/OrchardCore.DisplayManagement/Shapes/AlternatesCollection.cs#L87-L115","documentation":"AlternatesCollection is an immutable collection with a shared Empty singleton. Any mutation (Add, Remove, Clear, AddRange) on the Empty instance calls EnsureMutable, which throws NotSupportedException because the singleton must never change. Mutations must go through a mutable copy of the collection.","triggerScenarios":"Calling shape.Metadata.Alternates.Add(...), .Remove(...), .Clear(), or .AddRange(...) when Alternates is the static Empty collection — typically on a freshly created shape whose alternates were never initialized, or after alternates were sealed.","commonSituations":"Custom shape-metadata providers or handlers appending alternates during rendering; code assuming Alternates is always a mutable List<string>; adding placement alternates late in the pipeline.","solutions":["Assign a new mutable collection first: shape.Metadata.Alternates = new AlternatesCollection(existing); then mutate","Use the collection's non-mutating APIs or create a new AlternatesCollection with the added items","Initialize alternates when the shape is built (before it reaches the sealed/Empty state)","Check for existing items and replace the Alternates reference rather than mutating the shared Empty"],"exampleFix":"// before\nshape.Metadata.Alternates.Add(shape.Metadata.Type + \"_Custom\");\n// after\nshape.Metadata.Alternates = new AlternatesCollection(\n    shape.Metadata.Alternates.Append(shape.Metadata.Type + \"_Custom\"));","handlingStrategy":"validation","validationCode":"if (shape.Metadata.Alternates == AlternatesCollection.Empty)\n{\n    shape.Metadata.Alternates = new AlternatesCollection();\n}\nshape.Metadata.Alternates.Add(alternateName);","typeGuard":"bool AlternatesMutable(IShape shape) => shape.Metadata.Alternates != AlternatesCollection.Empty;","tryCatchPattern":"try { alternates.Add(name); } catch (NotSupportedException) { shape.Metadata.Alternates = new AlternatesCollection(alternates.Append(name)); }","preventionTips":["Treat AlternatesCollection as immutable; replace rather than mutate the shared Empty","Initialize alternates at shape creation time","Set custom alternates in shape metadata providers before rendering"],"tags":["shapes","immutability","alternates","display-management"],"backgroundTag":"unsupported-operation","analyzedSha":"4306c0717fe573f6fca1b4955909ddab6a192807","analyzedAt":"2026-09-13T17:41:05.024Z","contentChangedAt":"2026-09-13T17:41:05.024Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}