{"record":{"id":"719793f41ba7a507","repo":"antlr/antlr4","slug":"cannot-serialize-a-transition-to-a-removed-state","errorCode":null,"errorMessage":"Cannot serialize a transition to a removed state.","messagePattern":"Cannot serialize a transition to a removed state\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"runtime/Java/src/org/antlr/v4/runtime/atn/ATNSerializer.java","lineNumber":175,"sourceCode":"\t}\n\n\tprivate void addEdges(int nedges, Map<IntervalSet, Integer> setIndices) {\n\t\tdata.add(nedges);\n\t\tfor (ATNState s : atn.states) {\n\t\t\tif ( s==null ) {\n\t\t\t\t// might be optimized away\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (s.getStateType() == ATNState.RULE_STOP) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (int i=0; i<s.getNumberOfTransitions(); i++) {\n\t\t\t\tTransition t = s.transition(i);\n\n\t\t\t\tif (atn.states.get(t.target.stateNumber) == null) {\n\t\t\t\t\tthrow new IllegalStateException(\"Cannot serialize a transition to a removed state.\");\n\t\t\t\t}\n\n\t\t\t\tint src = s.stateNumber;\n\t\t\t\tint trg = t.target.stateNumber;\n\t\t\t\tint edgeType = Transition.serializationTypes.get(t.getClass());\n\t\t\t\tint arg1 = 0;\n\t\t\t\tint arg2 = 0;\n\t\t\t\tint arg3 = 0;\n\t\t\t\tswitch ( edgeType ) {\n\t\t\t\t\tcase Transition.RULE :\n\t\t\t\t\t\ttrg = ((RuleTransition)t).followState.stateNumber;\n\t\t\t\t\t\targ1 = ((RuleTransition)t).target.stateNumber;\n\t\t\t\t\t\targ2 = ((RuleTransition)t).ruleIndex;\n\t\t\t\t\t\targ3 = ((RuleTransition)t).precedence;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Transition.PRECEDENCE:\n\t\t\t\t\t\tPrecedencePredicateTransition ppt = (PrecedencePredicateTransition)t;\n\t\t\t\t\t\targ1 = ppt.precedence;","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Java/src/org/antlr/v4/runtime/atn/ATNSerializer.java#L157-L193","documentation":"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.","triggerScenarios":"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.","commonSituations":" 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.","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"],"exampleFix":"// before\natn.states.set(removedState.stateNumber, null); // leaves dangling transitions\nnew ATNSerializer(atn).serialize();\n// after\n// keep the ATN immutable; re-create it from the grammar instead of pruning states\nATNDeserializer d = new ATNDeserializer();\nATN cleanAtn = d.deserialize(ATNDeserializer.getSerializedAsString(oldAtn).chars());\nnew ATNSerializer(cleanAtn).serialize();","handlingStrategy":"validation","validationCode":"boolean isSerializable(ATN atn) {\n    for (ATNState s : atn.states) {\n        if (s == null) continue;\n        for (int i = 0; i < s.getNumberOfTransitions(); i++) {\n            Transition t = s.transition(i);\n            if (t.target == null || atn.states.get(t.target.stateNumber) == null) return false;\n        }\n    }\n    return true;\n}","typeGuard":null,"tryCatchPattern":"catch (IllegalStateException e) { if (e.getMessage().contains(\"removed state\")) { /* regenerate grammar/tool match, rebuild ATN */ } else throw e; }","preventionTips":["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"],"tags":["antlr","java","atn","serialization","corrupt-state"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}