antlr/antlr4 · error · InvalidOperationException

The object is read only.

Error message

The object is read only.

What it means

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.

Source

Thrown at runtime/CSharp/src/Atn/ATNDeserializationOptions.cs:112

        public bool Optimize
        {
            get
            {
                return optimize;
            }
            set
            {
                bool optimize = value;
                ThrowIfReadOnly();
                this.optimize = optimize;
            }
        }

        protected internal virtual void ThrowIfReadOnly()
        {
            if (IsReadOnly)
            {
                throw new InvalidOperationException("The object is read only.");
            }
        }
    }
}

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Create a fresh ATNDeserializationOptions instance per configuration (clone pattern), mutate, then let it be frozen
  2. Set all options before constructing/running the ATNDeserializer with them

Example fix

// before
var opts = ATNDeserializationOptions.Default;
opts.Optimize = true; // Default is read-only

// after
var opts = new ATNDeserializationOptions();
opts.Optimize = true;
opts.MakeReadOnly();
Defensive patterns

Strategy: validation

Validate before calling

if (!options.IsReadOnly) { options.Optimize = true; }

Type guard

static bool IsMutable(ATNDeserializationOptions o) => !o.IsReadOnly;

Try / catch

try { options.Optimize = true; } catch (InvalidOperationException) { /* frozen: create a fresh options instance instead */ }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14). Data as JSON: /api/errors/c7f672714dbf6a73. Report an issue: GitHub.