{"record":{"id":"ed94068e83220641","repo":"stanfordnlp/CoreNLP","slug":"can-t-have-null-topcat","errorCode":null,"errorMessage":"can't have null topcat","messagePattern":"can't have null topcat","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/parser/lexparser/GrammarCompactor.java","lineNumber":263,"sourceCode":"    if (op.trainOptions.markFinalStates) {\n      bracket = parentString.substring(parentString.length() - 1, parentString.length());\n    }\n    // the below test is not necessary with left to right grammars\n    if (isSyntheticState(leftString)) {\n      source = leftString;\n      input = rightString + (bracket == null ? \">\" : bracket);\n    } else if (isSyntheticState(rightString)) {\n      source = rightString;\n      input = leftString + (bracket == null ? \"<\" : bracket);\n    } else {\n      // we don't know what to do with this rule\n      return false;\n    }\n    target = parentString;\n    Double output = Double.valueOf(smartNegate(rule.score())); // makes it a real  0 <= k <= infty\n    String topcat = getTopCategoryOfSyntheticState(source);\n    if (topcat == null) {\n      throw new RuntimeException(\"can't have null topcat\");\n    }\n    TransducerGraph graph = getGraphFromMap(graphs, topcat);\n    graph.addArc(source, target, input, output);\n    return true;\n  }\n\n  protected static boolean isSyntheticState(String state) {\n    return state.charAt(0) == '@';\n  }\n\n\n  /**\n   * @param graphs      a Map from String categories to TransducerGraph objects\n   * @param unaryRules  is a Set of UnaryRule objects that we need to add\n   * @param binaryRules is a Set of BinaryRule objects that we need to add\n   * @return a new Pair of UnaryGrammar, BinaryGrammar\n   */\n  protected Pair<UnaryGrammar,BinaryGrammar> convertGraphsToGrammar(Set<TransducerGraph> graphs, Set<UnaryRule> unaryRules, Set<BinaryRule> binaryRules) {","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/parser/lexparser/GrammarCompactor.java#L245-L281","documentation":"addOneBinaryRule extracts the top category from a synthetic ( '@'-prefixed ) source state via getTopCategoryOfSyntheticState and requires it to be non-null to select the right per-topcat transducer graph. getTopCategoryOfSyntheticState returns null for non-'@' names, meaning a binary rule's source state was expected to be synthetic but wasn't — an internal invariant violation.","triggerScenarios":"Processing binary rules during graph construction where the source state name does not begin with '@' although the code path assumes a synthetic split state (e.g. corrupt or non-standard grammar input).","commonSituations":"Compacting a grammar whose binary-rule states weren't generated by the standard markovized-state naming scheme, often from mismatched training/compaction versions.","solutions":["Verify the grammar was produced by the standard training pipeline so binary rule states are '@'-prefixed synthetic states.","Regenerate the grammar file with the same library version used for compaction.","Disable compaction (compactGrammar = 0) for this grammar."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (!source.startsWith(\"@\")) throw new IllegalStateException(\"Expected synthetic state: \" + source);","typeGuard":null,"tryCatchPattern":"try { compactor.wasAdded(rule, graphs); } catch (RuntimeException e) { log.error(\"Invariant broken in compaction: \" + e.getMessage()); throw e; }","preventionTips":["Feed only grammars trained by the standard pipeline into GrammarCompactor","Match training and compaction library versions"],"tags":["grammar-compaction","invariant","parser","state-name"],"backgroundTag":"internal-invariant-violation","analyzedSha":"1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a","analyzedAt":"2026-09-10T02:24:07.274Z","contentChangedAt":"2026-09-10T02:24:07.274Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}