stanfordnlp/CoreNLP · error · ForwardPropagationException

We should not have reached leaves in forwardPropagate

Error message

We should not have reached leaves in forwardPropagate

What it means

During forward propagation in SentimentCostAndGradient, the recursion should stop at preterminals; leaves are never visited directly. Reaching a bare leaf means the tree is malformed (e.g. a degenerate single-leaf tree) and ForwardPropagationException is thrown.

Solutions

  1. Ensure trees are preprocessed so every leaf has a preterminal parent (e.g. via convertTrees/collapse handling)
  2. Filter out single-leaf degenerate trees from your training data
  3. Re-run dataset conversion with ReadSentimentDataset to produce well-formed binarized trees

Example fix

// before
Tree bad = Tree.valueOf("(word)"); // leaf with no preterminal
// after
Tree good = Tree.valueOf("(NN word)"); // preterminal wraps leaf
Defensive patterns

Strategy: validation

Validate before calling

boolean hasPreterminals(Tree t) { return t.isLeaf() ? false : t.isPreTerminal() || Arrays.stream(t.children()).allMatch(this::hasPreterminals); }
if (!hasPreterminals(root)) throw new IllegalStateException("Bare leaf without preterminal");

Try / catch

try { forwardPropagate(tree); } catch (ForwardPropagationException e) { if (e.getMessage().contains("leaves")) { sanitizeAndRetry(tree); } else throw e; }

Prevention

When it happens

Trigger: Training/evaluating on a tree whose preterminal node was dropped — e.g. a tree that is just a leaf word with no POS node, or trees not preprocessed with the expected collapsing/cleaning.

Common situations: Feeding raw parse trees that skipped binarization/collapsing, custom datasets built incorrectly, degenerate trees of one leaf noted in the source comment.

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/e4a775f3dc504611. Report an issue: GitHub.

Appendix: source

Thrown at src/edu/stanford/nlp/sentiment/SentimentCostAndGradient.java:502

  /**
   * This is the method to call for assigning labels and node vectors
   * to the Tree.  After calling this, each of the non-leaf nodes will
   * have the node vector and the predictions of their classes
   * assigned to that subtree's node.  The annotations filled in are
   * the RNNCoreAnnotations.NodeVector, Predictions, and
   * PredictedClass.  In general, PredictedClass will be the most
   * useful annotation except when training.
   */
  public void forwardPropagateTree(Tree tree) {
    SimpleMatrix nodeVector; // initialized below or Exception thrown // = null;
    SimpleMatrix classification; // initialized below or Exception thrown // = null;

    if (tree.isLeaf()) {
      // We do nothing for the leaves.  The preterminals will
      // calculate the classification for this word/tag.  In fact, the
      // recursion should not have gotten here (unless there are
      // degenerate trees of just one leaf)
      throw new ForwardPropagationException("We should not have reached leaves in forwardPropagate");
    } else if (tree.isPreTerminal()) {
      classification = model.getUnaryClassification(tree.label().value());
      String word = tree.children()[0].label().value();
      SimpleMatrix wordVector = model.getWordVector(word);
      nodeVector = NeuralUtils.elementwiseApplyTanh(wordVector);
    } else if (tree.children().length == 1) {
      throw new ForwardPropagationException("Non-preterminal nodes of size 1 should have already been collapsed");
    } else if (tree.children().length == 2) {
      forwardPropagateTree(tree.children()[0]);
      forwardPropagateTree(tree.children()[1]);

      String leftCategory = tree.children()[0].label().value();
      String rightCategory = tree.children()[1].label().value();
      SimpleMatrix W = model.getBinaryTransform(leftCategory, rightCategory);
      classification = model.getBinaryClassification(leftCategory, rightCategory);

      SimpleMatrix leftVector = RNNCoreAnnotations.getNodeVector(tree.children()[0]);
      SimpleMatrix rightVector = RNNCoreAnnotations.getNodeVector(tree.children()[1]);

View on GitHub (pinned to 1b7edd19c4)