antlr/antlr4 · error · IllegalArgumentException

The specified lexer action type %s is not valid.

Error message

The specified lexer action type %s is not valid.

What it means

ATNSerializer.addLexerActions serializes only the built-in LexerActionType cases. If atn.lexerActions contains a LexerAction whose getActionType() is not recognized by this switch, serialization cannot emit a valid action record and throws IllegalArgumentException. This points to a custom/future action type or mismatched runtime classes.

Source

Thrown at runtime/Java/src/org/antlr/v4/runtime/atn/ATNSerializer.java:145

					mode = ((LexerPushModeAction)action).getMode();
					data.add(mode);
					data.add(0);
					break;

				case SKIP:
					data.add(0);
					data.add(0);
					break;

				case TYPE:
					int type = ((LexerTypeAction)action).getType();
					data.add(type);
					data.add(0);
					break;

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

	private void addDecisionStartStates() {
		int ndecisions = atn.decisionToState.size();
		data.add(ndecisions);
		for (DecisionState decStartState : atn.decisionToState) {
			data.add(decStartState.stateNumber);
		}
	}

	private void addEdges(int nedges, Map<IntervalSet, Integer> setIndices) {
		data.add(nedges);
		for (ATNState s : atn.states) {
			if ( s==null ) {
				// might be optimized away

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Represent custom behavior with LexerCustomAction instead of a new LexerActionType.
  2. If forking ANTLR, update LexerActionType, ATNSerializer, and ATNDeserializer together.
  3. Ensure every LexerAction class comes from the same runtime jar as ATNSerializer.
  4. Validate each action type against the built-in set before serialization.

Example fix

// before
atn.lexerActions[i] = customActionWithUnsupportedType;
IntegerList data = ATNSerializer.getSerialized(atn);

// after
atn.lexerActions[i] = new LexerCustomAction(ruleIndex, actionIndex);
IntegerList data = ATNSerializer.getSerialized(atn);
Defensive patterns

Strategy: validation

Validate before calling

static boolean usesBuiltInLexerActionType(LexerAction action) {
    switch (action.getActionType()) {
        case CHANNEL:
        case CUSTOM:
        case MODE:
        case MORE:
        case POP_MODE:
        case PUSH_MODE:
        case SKIP:
        case TYPE:
            return true;
        default:
            return false;
    }
}

Try / catch

try {
    return ATNSerializer.getSerialized(atn);
} catch (IllegalArgumentException e) {
    throw new IllegalStateException("ATN contains a lexer action type this serializer cannot write", e);
}

Prevention

When it happens

Trigger: Calling ATNSerializer.getSerialized(atn) after inserting a custom LexerAction implementation or an action loaded from an incompatible ANTLR runtime; running with classpath shadowing that mixes LexerAction implementations and serializer versions.

Common situations: Custom lexer runtime extensions, experimental ANTLR forks, and multiple/conflicting antlr4-runtime jars.

Related errors


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