antlr/antlr4 · error · Exception

The object is read only.

Error message

The object is read only.

What it means

ATNDeserializationOptions is a tiny read-only value object: after construction it can be mutated, but the module-level defaultOptions instance is frozen by setting readonly=True. Any attempt to set another attribute on a readonly instance (the custom __setattr__ blocks it) raises this Exception. In practice you hit it by mutating ATNDeserializationOptions.defaultOptions instead of making a copy.

Source

Thrown at runtime/Python3/src/antlr4/atn/ATNDeserializationOptions.py:20

# Use of this file is governed by the BSD 3-clause license that
# can be found in the LICENSE.txt file in the project root.

# need a forward declaration
ATNDeserializationOptions = None

class ATNDeserializationOptions(object):
    __slots__ = ('readonly', 'verifyATN', 'generateRuleBypassTransitions')

    defaultOptions = None

    def __init__(self, copyFrom:ATNDeserializationOptions = None):
        self.readonly = False
        self.verifyATN = True if copyFrom is None else copyFrom.verifyATN
        self.generateRuleBypassTransitions = False if copyFrom is None else copyFrom.generateRuleBypassTransitions

    def __setattr__(self, key, value):
        if key!="readonly" and self.readonly:
            raise Exception("The object is read only.")
        super(type(self), self).__setattr__(key,value)

ATNDeserializationOptions.defaultOptions = ATNDeserializationOptions()
ATNDeserializationOptions.defaultOptions.readonly = True

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Copy first, then mutate, then pass explicitly: opts = ATNDeserializationOptions(ATNDeserializationOptions.defaultOptions); opts.verifyATN = False; ATNDeserializer(opts).deserialize(data).
  2. Only touch the copy's flags (verifyATN, generateRuleBypassTransitions); never reassign attributes on defaultOptions itself.

Example fix

# before
ATNDeserializationOptions.defaultOptions.verifyATN = False  # Exception: read only

# after
from antlr4.atn.ATNDeserializationOptions import ATNDeserializationOptions
opts = ATNDeserializationOptions(ATNDeserializationOptions.defaultOptions)
opts.verifyATN = False
deserializer = ATNDeserializer(opts)
Defensive patterns

Strategy: validation

Validate before calling

def mutable_options(**flags):
    opts = ATNDeserializationOptions(ATNDeserializationOptions.defaultOptions)
    for k, v in flags.items():
        setattr(opts, k, v)  # safe: copy is not readonly
    return opts

Prevention

When it happens

Trigger: ATNDeserializationOptions.defaultOptions.verifyATN = False, or defaultOptions.generateRuleBypassTransitions = True — direct mutation of the frozen singleton.

Common situations: Trying to disable ATN verification or enable rule bypass transitions for the whole process by editing defaultOptions; code copied from the Java runtime where options are cloned.

Related errors


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