{"record":{"id":"c7f672714dbf6a73","repo":"antlr/antlr4","slug":"the-object-is-read-only-c7f672","errorCode":null,"errorMessage":"The object is read only.","messagePattern":"The object is read only\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"runtime/CSharp/src/Atn/ATNDeserializationOptions.cs","lineNumber":112,"sourceCode":"        public bool Optimize\n        {\n            get\n            {\n                return optimize;\n            }\n            set\n            {\n                bool optimize = value;\n                ThrowIfReadOnly();\n                this.optimize = optimize;\n            }\n        }\n\n        protected internal virtual void ThrowIfReadOnly()\n        {\n            if (IsReadOnly)\n            {\n                throw new InvalidOperationException(\"The object is read only.\");\n            }\n        }\n    }\n}\n","sourceCodeStart":94,"sourceCodeEnd":117,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/CSharp/src/Atn/ATNDeserializationOptions.cs#L94-L117","documentation":"ATNDeserializationOptions is a mutable options object that gets frozen (MakeReadOnly / IsReadOnly) after configuration. Every setter routes through ThrowIfReadOnly(), which throws InvalidOperationException('The object is read only.') if you mutate a frozen instance. Freezing prevents options from changing mid-deserialization.","triggerScenarios":"Calling e.g. options.Optimize = true or options.VerifyATN = false after options.MakeReadOnly() was invoked — including when a default/shared instance (Default or the one inside ATNDeserializer) was already frozen.","commonSituations":"Reusing ATNDeserializer.DefaultOptions or a static options instance across deserializations and trying to tweak it per call; copying sample code that mutates options after passing them to a deserializer that freezes them.","solutions":["Create a fresh ATNDeserializationOptions instance per configuration (clone pattern), mutate, then let it be frozen","Set all options before constructing/running the ATNDeserializer with them"],"exampleFix":"// before\nvar opts = ATNDeserializationOptions.Default;\nopts.Optimize = true; // Default is read-only\n\n// after\nvar opts = new ATNDeserializationOptions();\nopts.Optimize = true;\nopts.MakeReadOnly();","handlingStrategy":"validation","validationCode":"if (!options.IsReadOnly) { options.Optimize = true; }","typeGuard":"static bool IsMutable(ATNDeserializationOptions o) => !o.IsReadOnly;","tryCatchPattern":"try { options.Optimize = true; } catch (InvalidOperationException) { /* frozen: create a fresh options instance instead */ }","preventionTips":["Never mutate Default/shared options instances; construct fresh ones","Configure options fully before handing them to ATNDeserializer"],"tags":["antlr","atn","immutability","csharp"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}