antlr/antlr4 · critical · UnsupportedOperationException

Could not deserialize ATN with version %d (expected %d).

Error message

Could not deserialize ATN with version %d (expected %d).

What it means

Serialized ATN data starts with a format version. This runtime expects ATNDeserializer.SERIALIZED_VERSION (4 in this source); if the generated or supplied serialized ATN carries a different version, it cannot be safely interpreted and UnsupportedOperationException wraps an InvalidClassException. The ATN never becomes usable with this runtime.

Source

Thrown at runtime/Java/src/org/antlr/v4/runtime/atn/ATNDeserializer.java:56

	public ATNDeserializer(ATNDeserializationOptions deserializationOptions) {
		if (deserializationOptions == null) {
			deserializationOptions = ATNDeserializationOptions.getDefaultOptions();
		}

		this.deserializationOptions = deserializationOptions;
	}

	public ATN deserialize(char[] data) {
		return deserialize(decodeIntsEncodedAs16BitWords(data));
	}

	public ATN deserialize(int[] data) {
		int p = 0;
		int version = data[p++];
		if (version != SERIALIZED_VERSION) {
			String reason = String.format(Locale.getDefault(), "Could not deserialize ATN with version %d (expected %d).", version, SERIALIZED_VERSION);
			throw new UnsupportedOperationException(new InvalidClassException(ATN.class.getName(), reason));
		}

		ATNType grammarType = ATNType.values()[data[p++]];
		int maxTokenType = data[p++];
		ATN atn = new ATN(grammarType, maxTokenType);

		//
		// STATES
		//
		List<Pair<LoopEndState, Integer>> loopBackStateNumbers = new ArrayList<Pair<LoopEndState, Integer>>();
		List<Pair<BlockStartState, Integer>> endStateNumbers = new ArrayList<Pair<BlockStartState, Integer>>();
		int nstates = data[p++];
		for (int i=0; i<nstates; i++) {
			int stype = data[p++];
			// ignore bad type of states
			if ( stype==ATNState.INVALID_TYPE ) {
				atn.addState(null);
				continue;

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Make the ANTLR generation tool and antlr4-runtime use the same release.
  2. Regenerate all parser and lexer sources from the grammar, then clean-rebuild.
  3. Inspect the dependency tree and remove duplicate/conflicting ANTLR runtime versions.
  4. For custom serialized data, decode it and verify the first integer equals ATNDeserializer.SERIALIZED_VERSION before deserializing.

Example fix

// before: parser generated by an older ANTLR tool
new MyParser(new CommonTokenStream(new MyLexer(input))).start();

// after: regenerate MyLexer/MyParser with the same antlr version as the runtime, clean build outputs, then run
MyParser parser = new MyParser(new CommonTokenStream(new MyLexer(input)));
parser.start();
Defensive patterns

Strategy: validation

Validate before calling

static boolean hasCompatibleAtnVersion(char[] serialized) {
    int[] data = ATNDeserializer.decodeIntsEncodedAs16BitWords(serialized);
    return data.length > 0 && data[0] == ATNDeserializer.SERIALIZED_VERSION;
}

Try / catch

try {
    return new ATNDeserializer(options).deserialize(serialized);
} catch (UnsupportedOperationException e) {
    if (e.getCause() instanceof InvalidClassException) {
        throw new IllegalStateException("Generated parser and ANTLR runtime versions differ; regenerate sources", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Passing a _serializedATN string generated by a different ANTLR tool version; running generated parser classes from one release with an antlr4-runtime jar from another; manually loading serialized ATN bytes/chars from an incompatible source.

Common situations: Upgrading the runtime without regenerating parser/lexer sources, stale build output, dependency shading that selects an old runtime, or copying generated code between projects built with different ANTLR versions.

Related errors


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