antlr/antlr4 · critical · IllegalArgumentException

The specified lexer action type %s is not valid.

Error message

The specified lexer action type %s is not valid.

What it means

For lexer ATNs, lexerActionFactory constructs actions only for the built-in LexerActionType values CHANNEL, CUSTOM, MODE, MORE, POP_MODE, PUSH_MODE, SKIP, and TYPE. An unrecognized action type indicates incompatible or malformed serialized lexer action data. In practice this usually means lexer/runtime classes from different ANTLR versions are mixed.

Source

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

			return new LexerModeAction(data1);

		case MORE:
			return LexerMoreAction.INSTANCE;

		case POP_MODE:
			return LexerPopModeAction.INSTANCE;

		case PUSH_MODE:
			return new LexerPushModeAction(data1);

		case SKIP:
			return LexerSkipAction.INSTANCE;

		case TYPE:
			return new LexerTypeAction(data1);

		default:
			throw new IllegalArgumentException(String.format(Locale.getDefault(), "The specified lexer action type %s is not valid.", type));
		}
	}

	/** Given a list of integers representing a serialized ATN, encode values too large to fit into 15 bits
	 *  as two 16bit values. We use the high bit (0x8000_0000) to indicate values requiring two 16 bit words.
	 *  If the high bit is set, we grab the next value and combine them to get a 31-bit value. The possible
	 *  input int values are [-1,0x7FFF_FFFF].
	 *
	 * 		| compression/encoding                         | uint16 count | type            |
	 * 		| -------------------------------------------- | ------------ | --------------- |
	 * 		| 0xxxxxxx xxxxxxxx                            | 1            | uint (15 bit)   |
	 * 		| 1xxxxxxx xxxxxxxx yyyyyyyy yyyyyyyy          | 2            | uint (16+ bits) |
	 * 		| 11111111 11111111 11111111 11111111          | 2            | int value -1    |
	 *
	 * 	This is only used (other than for testing) by {@link org.antlr.v4.codegen.model.SerializedJavaATN}
	 * 	to encode ints as char values for the java target, but it is convenient to combine it with the
	 * 	#decodeIntsEncodedAs16BitWords that follows as they are a pair (I did not want to introduce a new class
	 * 	into the runtime). Used only for Java Target.

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Align the ANTLR tool, generated lexer, and antlr4-runtime on one version.
  2. Regenerate all lexer/parser sources and clean-build.
  3. Inspect dependencies for duplicate or shaded ANTLR runtimes.
  4. Do not manually edit serialized lexer action records.

Example fix

// before: generated lexer from one ANTLR version, runtime from another
new MyLexer(input);

// after: regenerate MyLexer with the runtime's ANTLR version and remove duplicate runtime jars
new MyLexer(input);
Defensive patterns

Strategy: try-catch

Try / catch

try {
    return new ATNDeserializer(options).deserialize(serialized);
} catch (IllegalArgumentException e) {
    throw new IllegalStateException("Lexer action data is incompatible with this ANTLR runtime", e);
}

Prevention

When it happens

Trigger: Deserializing a lexer ATN whose lexer-action ordinal was encoded by a different runtime/ANTLR build; corrupted serialized data causing an invalid enum/action code; or classpath shadowing that loads mismatched LexerActionType and ATNDeserializer classes.

Common situations: Multiple antlr4-runtime versions, stale generated lexers, shading conflicts, and custom serialized ATN data.

Related errors


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