{"record":{"id":"d941727ee09ee1bb","repo":"stanfordnlp/CoreNLP","slug":"expected-tree-labels-to-have-their-heads-assigned","errorCode":null,"errorMessage":"Expected tree labels to have their heads assigned.  Failed at: <tree>","messagePattern":"Expected tree labels to have their heads assigned\\.  Failed at: <tree>","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/parser/shiftreduce/CreateTransitionSequence.java","lineNumber":84,"sourceCode":"\n      // This is the tricky part... need to decide if the binary\n      // transition is a left or right transition.  This is done by\n      // looking at the existing heads of this node and its two\n      // children.  The expectation is that the tree already has heads\n      // assigned; otherwise, exception is thrown\n      if (!(tree.label() instanceof CoreLabel) || \n          !(tree.children()[0].label() instanceof CoreLabel) ||\n          !(tree.children()[1].label() instanceof CoreLabel)) {\n        throw new IllegalArgumentException(\"Expected tree labels to be CoreLabel\");\n      }\n      CoreLabel label = (CoreLabel) tree.label();\n      CoreLabel leftLabel = (CoreLabel) tree.children()[0].label();\n      CoreLabel rightLabel = (CoreLabel) tree.children()[1].label();\n      CoreLabel head = label.get(TreeCoreAnnotations.HeadWordLabelAnnotation.class);\n      CoreLabel leftHead = leftLabel.get(TreeCoreAnnotations.HeadWordLabelAnnotation.class);\n      CoreLabel rightHead = rightLabel.get(TreeCoreAnnotations.HeadWordLabelAnnotation.class);\n      if (head == null || leftHead == null || rightHead == null) {\n        throw new IllegalArgumentException(\"Expected tree labels to have their heads assigned.  Failed at: \" + tree);\n      }\n      boolean isRoot = rootOnlyStates.contains(tree.label().value());\n      if (head == leftHead) {\n        transitions.add(new BinaryTransition(tree.label().value(), BinaryTransition.Side.LEFT, isRoot));\n      } else if (head == rightHead) {\n        transitions.add(new BinaryTransition(tree.label().value(), BinaryTransition.Side.RIGHT, isRoot));\n      } else {\n        throw new IllegalArgumentException(\"Heads were incorrectly assigned: tree's head is not matched to either the right or left head\");\n      }\n    } else {\n      throw new IllegalArgumentException(\"Expected a binarized tree\");\n    }\n  }\n}\n","sourceCodeStart":66,"sourceCodeEnd":99,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/parser/shiftreduce/CreateTransitionSequence.java#L66-L99","documentation":"After confirming the labels are CoreLabel, createTransitionSequenceHelper() reads TreeCoreAnnotations.HeadWordLabelAnnotation from the node and both children to decide the binary transition direction. If any head annotation is null, the tree's heads were never assigned, and it throws this IllegalArgumentException including the offending tree in the message.","triggerScenarios":"Generating transition sequences from trees that skipped the head-finding step (e.g. no SemanticGraphHeadFinder/HeadFinder pass) — heads are null for the node or either child.","commonSituations":"Training pipelines that load trees from a treebank file but forget the 'head-finding' preprocessing the shift-reduce trainer normally applies, or trees reconstructed programmatically without head annotations.","solutions":["Run head finding on the binarized tree before generating transitions (same preprocessing as ShiftReduceParser training).","Use the library's training entry point rather than calling createTransitionSequence directly on raw treebank trees.","Programmatically assign heads: apply a HeadFinder and set TreeCoreAnnotations.HeadWordLabelAnnotation on each node.","Check the tree printed in the exception to find the node missing its head."],"exampleFix":"// before\nList<Transition> trans = createTransitionSequence(tree, false, rootStates, null);\n// after\nTrainOptions opts = new TrainOptions();\nList<Tree> prep = ShiftReduceParser.preprocessTrees(Collections.singletonList(tree), opts);\nList<Transition> trans = createTransitionSequence(prep.get(0), false, rootStates, null);","handlingStrategy":"validation","validationCode":"CoreLabel lbl = (CoreLabel) tree.label();\nif (lbl.get(TreeCoreAnnotations.HeadWordLabelAnnotation.class) == null)\n    throw new IllegalArgumentException(\"Run head-finding before generating transitions: \" + tree);","typeGuard":"boolean hasHeadsAssigned(Tree t) {\n    if (!(t.label() instanceof CoreLabel)) return false;\n    if (((CoreLabel) t.label()).get(TreeCoreAnnotations.HeadWordLabelAnnotation.class) == null) return false;\n    for (Tree c : t.children()) if (!hasHeadsAssigned(c)) return false;\n    return true;\n}","tryCatchPattern":"try {\n    List<Transition> trans = CreateTransitionSequence.createTransitionSequence(tree, false, rootStates, null);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Expected tree labels to have their heads assigned\")) {\n        // apply head finding to the offending tree, then retry\n    }\n}","preventionTips":["Always run the trainer's head-finding preprocessing on binarized trees.","Check for HeadWordLabelAnnotation before sequence generation.","Use the exception's embedded tree to locate the node missing heads."],"tags":["java","missing-annotation","training","nlp"],"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"}