{"record":{"id":"e4a775f3dc504611","repo":"stanfordnlp/CoreNLP","slug":"we-should-not-have-reached-leaves-in-forwardpropag","errorCode":null,"errorMessage":"We should not have reached leaves in forwardPropagate","messagePattern":"We should not have reached leaves in forwardPropagate","errorType":"exception","errorClass":"ForwardPropagationException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/sentiment/SentimentCostAndGradient.java","lineNumber":502,"sourceCode":"  /**\n   * This is the method to call for assigning labels and node vectors\n   * to the Tree.  After calling this, each of the non-leaf nodes will\n   * have the node vector and the predictions of their classes\n   * assigned to that subtree's node.  The annotations filled in are\n   * the RNNCoreAnnotations.NodeVector, Predictions, and\n   * PredictedClass.  In general, PredictedClass will be the most\n   * useful annotation except when training.\n   */\n  public void forwardPropagateTree(Tree tree) {\n    SimpleMatrix nodeVector; // initialized below or Exception thrown // = null;\n    SimpleMatrix classification; // initialized below or Exception thrown // = null;\n\n    if (tree.isLeaf()) {\n      // We do nothing for the leaves.  The preterminals will\n      // calculate the classification for this word/tag.  In fact, the\n      // recursion should not have gotten here (unless there are\n      // degenerate trees of just one leaf)\n      throw new ForwardPropagationException(\"We should not have reached leaves in forwardPropagate\");\n    } else if (tree.isPreTerminal()) {\n      classification = model.getUnaryClassification(tree.label().value());\n      String word = tree.children()[0].label().value();\n      SimpleMatrix wordVector = model.getWordVector(word);\n      nodeVector = NeuralUtils.elementwiseApplyTanh(wordVector);\n    } else if (tree.children().length == 1) {\n      throw new ForwardPropagationException(\"Non-preterminal nodes of size 1 should have already been collapsed\");\n    } else if (tree.children().length == 2) {\n      forwardPropagateTree(tree.children()[0]);\n      forwardPropagateTree(tree.children()[1]);\n\n      String leftCategory = tree.children()[0].label().value();\n      String rightCategory = tree.children()[1].label().value();\n      SimpleMatrix W = model.getBinaryTransform(leftCategory, rightCategory);\n      classification = model.getBinaryClassification(leftCategory, rightCategory);\n\n      SimpleMatrix leftVector = RNNCoreAnnotations.getNodeVector(tree.children()[0]);\n      SimpleMatrix rightVector = RNNCoreAnnotations.getNodeVector(tree.children()[1]);","sourceCodeStart":484,"sourceCodeEnd":520,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/sentiment/SentimentCostAndGradient.java#L484-L520","documentation":"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.","triggerScenarios":"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.","commonSituations":"Feeding raw parse trees that skipped binarization/collapsing, custom datasets built incorrectly, degenerate trees of one leaf noted in the source comment.","solutions":["Ensure trees are preprocessed so every leaf has a preterminal parent (e.g. via convertTrees/collapse handling)","Filter out single-leaf degenerate trees from your training data","Re-run dataset conversion with ReadSentimentDataset to produce well-formed binarized trees"],"exampleFix":"// before\nTree bad = Tree.valueOf(\"(word)\"); // leaf with no preterminal\n// after\nTree good = Tree.valueOf(\"(NN word)\"); // preterminal wraps leaf","handlingStrategy":"validation","validationCode":"boolean hasPreterminals(Tree t) { return t.isLeaf() ? false : t.isPreTerminal() || Arrays.stream(t.children()).allMatch(this::hasPreterminals); }\nif (!hasPreterminals(root)) throw new IllegalStateException(\"Bare leaf without preterminal\");","typeGuard":null,"tryCatchPattern":"try { forwardPropagate(tree); } catch (ForwardPropagationException e) { if (e.getMessage().contains(\"leaves\")) { sanitizeAndRetry(tree); } else throw e; }","preventionTips":["Ensure preprocessing attaches POS preterminals to every leaf","Filter degenerate single-leaf trees from data","Run dataset conversion rather than feeding raw trees"],"tags":["neural-network","tree-structure"],"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-17T15:17:12.973Z"}