antlr/antlr4 · critical · Exception

Could not deserialize ATN with version {} (expected {}).

Error message

Could not deserialize ATN with version {} (expected {}).

What it means

The serialized ATN every generated parser/lexer embeds starts with a format version stamp; the runtime refuses to deserialize data stamped with a different SERIALIZED_VERSION than the one it supports. This is the primary guard against tool/runtime version skew: a grammar generated by an older or newer ANTLR tool produces an ATN the runtime cannot safely interpret.

Source

Thrown at runtime/Python3/src/antlr4/atn/ATNDeserializer.py:50

        self.readModes(atn)
        sets = []
        self.readSets(atn, sets)
        self.readEdges(atn, sets)
        self.readDecisions(atn)
        self.readLexerActions(atn)
        self.markPrecedenceDecisions(atn)
        self.verifyATN(atn)
        if self.deserializationOptions.generateRuleBypassTransitions \
                and atn.grammarType == ATNType.PARSER:
            self.generateRuleBypassTransitions(atn)
            # re-verify after modification
            self.verifyATN(atn)
        return atn

    def checkVersion(self):
        version = self.readInt()
        if version != SERIALIZED_VERSION:
            raise Exception("Could not deserialize ATN with version {} (expected {}).".format(ord(version), SERIALIZED_VERSION))

    def readATN(self):
        idx = self.readInt()
        grammarType = ATNType.fromOrdinal(idx)
        maxTokenType = self.readInt()
        return ATN(grammarType, maxTokenType)

    def readStates(self, atn:ATN):
        loopBackStateNumbers = []
        endStateNumbers = []
        nstates = self.readInt()
        for i in range(0, nstates):
            stype = self.readInt()
            # ignore bad type of states
            if stype==ATNState.INVALID_TYPE:
                atn.addState(None)
                continue
            ruleIndex = self.readInt()

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Align versions: regenerate all lexers/parsers with the ANTLR tool whose SERIALIZED_VERSION matches the installed Python runtime (check pip show antlr4-python3-runtime vs the tool jar version).
  2. Pin both tool and runtime in your requirements/CI so they move together.
  3. After regenerating, clean out stale generated files (*.interp, *.tokens, old Parser.py/Lexer.py) so an old artifact cannot be imported by accident.

Example fix

# before: parser generated with ANTLR 4.7 tool, runtime 4.13 installed
# -> Exception: Could not deserialize ATN with version ...

# after: regenerate with matching tool and pin runtime
# java -jar antlr-4.13.2-complete.jar -Dlanguage=Python3 MyGrammar.g4
# pip install antlr4-python3-runtime==4.13.2
Defensive patterns

Strategy: try-catch

Validate before calling

import antlr4
from antlr4.atn.ATNDeserializer import SERIALIZED_VERSION
# preflight: compare the version stamp embedded in your generated file's serialized ATN with the runtime's
assert generated_serialized_atn[0] == chr(SERIALIZED_VERSION), 'regenerate grammar with ANTLR tool matching runtime %s' % antlr4.__version__

Try / catch

try:
    lexer = MyLexer(input_stream)
except Exception as e:
    if 'Could not deserialize ATN with version' in str(e):
        raise RuntimeError('ANTLR tool/runtime version mismatch: regenerate parsers for runtime ' + antlr4.__version__)
    raise

Prevention

When it happens

Trigger: ATNDeserializer.deserialize() on serialized ATN from a generated Lexer.py/Parser.py built by a different ANTLR tool version than the installed antlr4-python3-runtime package.

Common situations: Upgrading the pip runtime without regenerating parsers (or vice versa); vendoring generated files from another project; mixing antlr4ts/Java-generated artifacts with the Python runtime; CI using a pinned old runtime against freshly generated code.

Related errors


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