{"record":{"id":"88b95dd366752bd1","repo":"antlr/antlr4","slug":"can-t-alter-readonly-intervalset-88b95d","errorCode":null,"errorMessage":"can't alter readonly IntervalSet","messagePattern":"can't alter readonly IntervalSet","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"runtime/CSharp/src/Misc/IntervalSet.cs","lineNumber":96,"sourceCode":"        {\n            Antlr4.Runtime.Misc.IntervalSet s = new Antlr4.Runtime.Misc.IntervalSet();\n            s.Add(a);\n            return s;\n        }\n\n        /// <summary>Create a set with all ints within range [a..b] (inclusive)</summary>\n        public static Antlr4.Runtime.Misc.IntervalSet Of(int a, int b)\n        {\n            Antlr4.Runtime.Misc.IntervalSet s = new Antlr4.Runtime.Misc.IntervalSet();\n            s.Add(a, b);\n            return s;\n        }\n\n        public virtual void Clear()\n        {\n            if (@readonly)\n            {\n                throw new InvalidOperationException(\"can't alter readonly IntervalSet\");\n            }\n            intervals.Clear();\n        }\n\n        /// <summary>Add a single element to the set.</summary>\n        /// <remarks>\n        /// Add a single element to the set.  An isolated element is stored\n        /// as a range el..el.\n        /// </remarks>\n        public virtual void Add(int el)\n        {\n            if (@readonly)\n            {\n                throw new InvalidOperationException(\"can't alter readonly IntervalSet\");\n            }\n            Add(el, el);\n        }\n","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/CSharp/src/Misc/IntervalSet.cs#L78-L114","documentation":"IntervalSet instances that the runtime publishes as shared constants are marked read-only; mutating them would corrupt every grammar and recognizer that shares the same set (e.g. the universal 'all tokens' or 'no tokens' sets). Clear() checks the read-only flag and throws InvalidOperationException instead of letting a shared constant be wiped.","triggerScenarios":"Calling Clear() on an IntervalSet obtained from runtime-owned state — typically error-recovery sets like recognizer.ErrorListener/DefaultErrorStrategy.GetErrorRecoverySet, ctx.exception.getExpectedTokens(), or transitions' label sets — rather than on a set you constructed yourself.","commonSituations":"Custom error strategies that want to reuse and clear an expected-tokens set; copying ATN structures and mutating the source's label sets; tests that mutate parser-time interval sets to simulate grammars.","solutions":["Never mutate sets you did not construct; create your own set and copy: var mine = new IntervalSet(theirs)","If you need to modify a set, clone it first with the IntervalSet copy constructor, which yields a writable set","Keep your mutable sets locally scoped and treat all runtime-returned IntervalSets as immutable"],"exampleFix":"// before\nIntervalSet expected = ctx.exception.GetExpectedTokens();\nexpected.Clear(); // may throw: read-only shared set\n\n// after\nIntervalSet expected = new IntervalSet(ctx.exception.GetExpectedTokens()); // writable copy\nexpected.Clear();","handlingStrategy":"validation","validationCode":"// Only clear sets you constructed; clone runtime-provided sets first\nIntervalSet writable = runtimeSet.IsReadOnly ? new IntervalSet(runtimeSet) : runtimeSet;\nwritable.Clear();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat every IntervalSet returned by the runtime (expected tokens, transition labels) as immutable","Use the IntervalSet copy constructor before mutating anything you didn't build"],"tags":["antlr","csharp","interval-set","immutability","shared-state"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}