antlr/antlr4 · error · IllegalStateException
Cannot serialize a transition to a removed state.
Error message
Cannot serialize a transition to a removed state.
What it means
Thrown by ATNSerializer while walking an ATN's transitions: a transition points at a state whose slot in atn.states is null (a state that was removed/never assigned). The ATN is a graph whose states are indexed in a list; serialization walks every state's outgoing edges and refuses to emit an edge to a null (removed) target. It signals a corrupted or internally inconsistent ATN, not a grammar-syntax problem.
Source
Thrown at runtime/Java/src/org/antlr/v4/runtime/atn/ATNSerializer.java:175
}
private void addEdges(int nedges, Map<IntervalSet, Integer> setIndices) {
data.add(nedges);
for (ATNState s : atn.states) {
if ( s==null ) {
// might be optimized away
continue;
}
if (s.getStateType() == ATNState.RULE_STOP) {
continue;
}
for (int i=0; i<s.getNumberOfTransitions(); i++) {
Transition t = s.transition(i);
if (atn.states.get(t.target.stateNumber) == null) {
throw new IllegalStateException("Cannot serialize a transition to a removed state.");
}
int src = s.stateNumber;
int trg = t.target.stateNumber;
int edgeType = Transition.serializationTypes.get(t.getClass());
int arg1 = 0;
int arg2 = 0;
int arg3 = 0;
switch ( edgeType ) {
case Transition.RULE :
trg = ((RuleTransition)t).followState.stateNumber;
arg1 = ((RuleTransition)t).target.stateNumber;
arg2 = ((RuleTransition)t).ruleIndex;
arg3 = ((RuleTransition)t).precedence;
break;
case Transition.PRECEDENCE:
PrecedencePredicateTransition ppt = (PrecedencePredicateTransition)t;
arg1 = ppt.precedence;View on GitHub (pinned to 7d5770395b)
Solutions
- Ensure the ANTLR jar used to generate the parser matches the runtime jar version exactly (e.g. both 4.13.1)
- If you build/modify ATNs programmatically, never remove states; keep atn.states fully populated and only add states via atn.addState so stateNumber stays consistent
- Re-generate the lexer/parser from the grammar with the current tool and re-serialize; do not reuse old serialized ATN data
- If you must remove a state, also remove/redirect every transition that targets it before serializing
Example fix
// before atn.states.set(removedState.stateNumber, null); // leaves dangling transitions new ATNSerializer(atn).serialize(); // after // keep the ATN immutable; re-create it from the grammar instead of pruning states ATNDeserializer d = new ATNDeserializer(); ATN cleanAtn = d.deserialize(ATNDeserializer.getSerializedAsString(oldAtn).chars()); new ATNSerializer(cleanAtn).serialize();
Defensive patterns
Strategy: validation
Validate before calling
boolean isSerializable(ATN atn) {
for (ATNState s : atn.states) {
if (s == null) continue;
for (int i = 0; i < s.getNumberOfTransitions(); i++) {
Transition t = s.transition(i);
if (t.target == null || atn.states.get(t.target.stateNumber) == null) return false;
}
}
return true;
} Try / catch
catch (IllegalStateException e) { if (e.getMessage().contains("removed state")) { /* regenerate grammar/tool match, rebuild ATN */ } else throw e; } Prevention
- Pin tool and runtime ANTLR versions to the same release
- Never mutate atn.states after deserialization
- Re-serialize only ATNs produced by ATNDeserializer from trusted data
When it happens
Trigger: Calling new ATNSerializer(atn).serialize() (or ATNSerializer.getSerializedAsString/atn) on an ATN whose states list contains null entries, or on an ATN that was hand-built / programmatically mutated so a Transition.target.stateNumber indexes a null slot. Also seen when a deserialized ATN is edited (states removed) and then re-serialized, or when tool and runtime versions produce/consume incompatible ATN shapes.
Common situations: Mixing ANTLR tool version X with runtime version Y so the deserialized ATN is malformed. Custom code that builds or prunes ATN states (e.g. experimental optimizers, ATN-faking for testing). Serializing an ATN obtained from ATNDeserializer after mutating atn.states.
Related errors
- Could not deserialize ATN with version %d (expected %d).
- Couldn't identify final state of the precedence rule prefix
- The specified transition type is not valid.
- The specified state type %d is not valid.
- Serialized ATN data element[i] = v doesn't fit in 31 bits
AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14).
Data as JSON: /api/errors/719793f41ba7a507.
Report an issue: GitHub.