stanfordnlp/CoreNLP · error · IllegalArgumentException

Trees not of equal length

Error message

Trees not of equal length

What it means

While propagating predicted labels, ExternalEvaluate iterates gold and predicted trees in parallel; the iterators must yield nodes in lockstep. If either iterator is exhausted while the other still has nodes (or a next() returns null), it throws IllegalArgumentException 'Trees not of equal length'.

Solutions

  1. Generate predicted trees with the same preprocessing (binarizer, filterUnknown) as the gold trees
  2. Verify each tree pair node-by-node (size/shape) before evaluation
  3. Check the prediction file for malformed or truncated trees

Example fix

// before
List<Tree> pred = SentimentUtils.readTreesWithGoldLabels(rawPredPath); // unbinarized
// after
TreeBinarizer b = TreeBinarizer.simpleTreeBinarizer(hf, tlp);
List<Tree> pred = rawTrees.stream().map(t -> b.transformTree(t)).collect(toList());
Defensive patterns

Strategy: validation

Validate before calling

for (int i = 0; i < gold.size(); i++) {
  if (gold.get(i).size() != pred.get(i).size())
    throw new IllegalArgumentException("Node-count mismatch at tree " + i);
}

Type guard

static boolean sameShape(Tree a, Tree b) { return a.size() == b.size(); }

Try / catch

try {
  externalEval.populatePredictedLabels(goldTrees);
} catch (IllegalArgumentException e) {
  log.error("Tree shape mismatch: " + e.getMessage());
}

Prevention

When it happens

Trigger: A gold/predicted tree pair with different numbers of nodes — e.g. predictions computed on non-binarized or differently preprocessed trees, or a truncated/malformed predicted tree.

Common situations: Predictions produced without the same binarization/filtering as the gold trees; tokenization differences changing tree shape; corrupted prediction output lines.

Related errors


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

Appendix: source

Thrown at src/edu/stanford/nlp/sentiment/ExternalEvaluate.java:40

  public ExternalEvaluate(RNNOptions op, List<Tree> predictedTrees) {
    super(op);
    this.predicted = predictedTrees;
  }

  @Override
  public void populatePredictedLabels(List<Tree> trees) {
    if (trees.size() != this.predicted.size()) {
      throw new IllegalArgumentException("Number of gold and predicted trees not equal!");
    }
    for (int i = 0; i < trees.size(); i++) {
      Iterator<Tree> goldTree = trees.get(i).iterator();
      Iterator<Tree> predictedTree = this.predicted.get(i).iterator();
      while (goldTree.hasNext() || predictedTree.hasNext()) {
        Tree goldNode = goldTree.next();
        Tree predictedNode = predictedTree.next();
        if (goldNode == null || predictedNode == null) {
          throw new IllegalArgumentException("Trees not of equal length");
        }
        if (goldNode.isLeaf()) {
          continue;
        }
        CoreLabel label = (CoreLabel) goldNode.label();
        label.set(RNNCoreAnnotations.PredictedClass.class,
                RNNCoreAnnotations.getPredictedClass(predictedNode));
      }
    }
  }

  /**
   * Expected arguments are {@code -gold gold -predicted predicted }
   *
   * For example <br>
   * {@code java edu.stanford.nlp.sentiment.ExternalEvaluate annotatedTrees.txt predictedTrees.txt }
   */
  public static void main(String[] args) {

View on GitHub (pinned to 1b7edd19c4)