stanfordnlp/CoreNLP · error · RuntimeException

can't have null topcat

Error message

can't have null topcat

What it means

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.

Solutions

  1. Verify the grammar was produced by the standard training pipeline so binary rule states are '@'-prefixed synthetic states.
  2. Regenerate the grammar file with the same library version used for compaction.
  3. Disable compaction (compactGrammar = 0) for this grammar.
Defensive patterns

Strategy: validation

Validate before calling

if (!source.startsWith("@")) throw new IllegalStateException("Expected synthetic state: " + source);

Try / catch

try { compactor.wasAdded(rule, graphs); } catch (RuntimeException e) { log.error("Invariant broken in compaction: " + e.getMessage()); throw e; }

Prevention

When it happens

Trigger: 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).

Common situations: Compacting a grammar whose binary-rule states weren't generated by the standard markovized-state naming scheme, often from mismatched training/compaction versions.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10). Data as JSON: /api/errors/ed94068e83220641. Report an issue: GitHub.

Appendix: source

Thrown at src/edu/stanford/nlp/parser/lexparser/GrammarCompactor.java:263

    if (op.trainOptions.markFinalStates) {
      bracket = parentString.substring(parentString.length() - 1, parentString.length());
    }
    // the below test is not necessary with left to right grammars
    if (isSyntheticState(leftString)) {
      source = leftString;
      input = rightString + (bracket == null ? ">" : bracket);
    } else if (isSyntheticState(rightString)) {
      source = rightString;
      input = leftString + (bracket == null ? "<" : bracket);
    } else {
      // we don't know what to do with this rule
      return false;
    }
    target = parentString;
    Double output = Double.valueOf(smartNegate(rule.score())); // makes it a real  0 <= k <= infty
    String topcat = getTopCategoryOfSyntheticState(source);
    if (topcat == null) {
      throw new RuntimeException("can't have null topcat");
    }
    TransducerGraph graph = getGraphFromMap(graphs, topcat);
    graph.addArc(source, target, input, output);
    return true;
  }

  protected static boolean isSyntheticState(String state) {
    return state.charAt(0) == '@';
  }


  /**
   * @param graphs      a Map from String categories to TransducerGraph objects
   * @param unaryRules  is a Set of UnaryRule objects that we need to add
   * @param binaryRules is a Set of BinaryRule objects that we need to add
   * @return a new Pair of UnaryGrammar, BinaryGrammar
   */
  protected Pair<UnaryGrammar,BinaryGrammar> convertGraphsToGrammar(Set<TransducerGraph> graphs, Set<UnaryRule> unaryRules, Set<BinaryRule> binaryRules) {

View on GitHub (pinned to 1b7edd19c4)