{"record":{"id":"e54ab6d0dc7a46d2","repo":"stanfordnlp/CoreNLP","slug":"binaryheadfinder-unexpected-tree","errorCode":null,"errorMessage":"BinaryHeadFinder: unexpected tree: ","messagePattern":"BinaryHeadFinder: unexpected tree: ","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/parser/lexparser/BinaryHeadFinder.java","lineNumber":37,"sourceCode":"  /**\n   * Determine which daughter of the current parse tree is the head.\n   * It assumes that the daughters already have had their heads\n   * determined. Another method has to do the tree walking.\n   *\n   * @param t The parse tree to examine the daughters of\n   * @return The parse tree that is the head.  The convention has been\n   *         that this returns <code>null</code> if no head is found.\n   *         But maybe it should throw an exception?\n   */\n  public Tree determineHead(Tree t) {\n    Tree result = determineBinaryHead(t);\n    if (result == null && fallbackHF != null) {\n      result = fallbackHF.determineHead(t);\n    }\n    if (result != null) {\n      return result;\n    }\n    throw new IllegalStateException(\"BinaryHeadFinder: unexpected tree: \" + t);\n  }\n  \n  public Tree determineHead(Tree t, Tree parent){\n    Tree result = determineBinaryHead(t);\n    if (result == null && fallbackHF != null) {\n      result = fallbackHF.determineHead(t, parent);\n    }\n    if (result != null) {\n      return result;\n    }\n    throw new IllegalStateException(\"BinaryHeadFinder: unexpected tree: \" + t);\n  }\n\n  private Tree determineBinaryHead(Tree t) {\n    if (t.numChildren() == 1) {\n      return t.firstChild();\n    } else {\n      String lval = t.firstChild().label().value();","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/parser/lexparser/BinaryHeadFinder.java#L19-L55","documentation":"BinaryHeadFinder.determineHead finds the head daughter of an already binarized tree: the only child, a child labeled with '@' (binarization marker), or the boundary child. If none applies and no fallback HeadFinder resolves it, it throws IllegalStateException naming the offending tree.","triggerScenarios":"Calling determineHead(t) on a binarized tree with 2+ children where neither the left child's label nor the right child's label starts with '@' and the rightmost child is not the BOUNDARY tag, with fallbackHF null or the fallback also returning null.","commonSituations":"Applying BinaryHeadFinder to non-binarized trees (e.g., raw Penn Treebank trees without '@' annotations), building the finder without a fallback head finder, custom tree transformations that strip '@' labels.","solutions":["Construct BinaryHeadFinder with an appropriate fallback HeadFinder, e.g. new BinaryHeadFinder(new SemanticHeadFinder()) or the head finder matching your treebank","Ensure trees are binarized (labels contain '@' on generated intermediate nodes) before head finding","Use the treebank's normal HeadFinder instead of BinaryHeadFinder for unbinarized trees","Log/print tree t from the exception message to see the unexpected structure and fix the upstream transformation"],"exampleFix":"// before\nHeadFinder hf = new BinaryHeadFinder();\n// after\nHeadFinder hf = new BinaryHeadFinder(new SemanticHeadFinder());","handlingStrategy":"fallback","validationCode":"// ensure trees are binarized before head finding\nif (tree.depth() > 0 && tree.children().length > 2)\n  throw new IllegalArgumentException(\"Tree not binarized: \" + tree);","typeGuard":"boolean isBinarized(Tree t) {\n  return t.isLeaf() || t.isPreTerminal() || t.numChildren() <= 2 ||\n         t.firstChild().label().value().startsWith(\"@\");\n}","tryCatchPattern":"try { head = bhf.determineHead(t); } catch (IllegalStateException e) { head = semanticHF.determineHead(t); }","preventionTips":["Always construct BinaryHeadFinder with a fallback HeadFinder","Only apply it to binarized trees","Test head finding on a sample of your treebank before full pipelines"],"tags":["parser","treebank","head-finding","illegal-state"],"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"}