{"record":{"id":"f878bb555102cf4d","repo":"stanfordnlp/CoreNLP","slug":"classes-derived-from-abstractcollinsheadfinder-mus","errorCode":null,"errorMessage":"Classes derived from AbstractCollinsHeadFinder must create and fill HashMap nonTerminalInfo.","messagePattern":"Classes derived from AbstractCollinsHeadFinder must create and fill HashMap nonTerminalInfo\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/trees/AbstractCollinsHeadFinder.java","lineNumber":161,"sourceCode":"  public Tree determineHead(Tree t) {\n    return determineHead(t, null);\n  }\n\n  /**\n   * Determine which daughter of the current parse tree is the head.\n   *\n   * @param t The parse tree to examine the daughters of.\n   *          If this is a leaf, {@code null} is returned\n   * @param parent The parent of t\n   * @return The daughter parse tree that is the head of {@code t}.\n   *   Returns null for leaf nodes.\n   * @see Tree#percolateHeads(HeadFinder)\n   *      for a routine to call this and spread heads throughout a tree\n   */\n  @Override\n  public Tree determineHead(Tree t, Tree parent) {\n    if (nonTerminalInfo == null) {\n      throw new IllegalStateException(\"Classes derived from AbstractCollinsHeadFinder must create and fill HashMap nonTerminalInfo.\");\n    }\n    if (t == null || t.isLeaf()) {\n      throw new IllegalArgumentException(\"Can't return head of null or leaf Tree.\");\n    }\n    if (DEBUG) {\n      log.info(\"determineHead for \" + t.value());\n    }\n\n    Tree[] kids = t.children();\n\n    Tree theHead;\n    // first check if subclass found explicitly marked head\n    if ((theHead = findMarkedHead(t)) != null) {\n      if (DEBUG) {\n        log.info(\"Find marked head method returned \" +\n                           theHead.label() + \" as head of \" + t.label());\n      }\n      return theHead;","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/trees/AbstractCollinsHeadFinder.java#L143-L179","documentation":"AbstractCollinsHeadFinder.determineHead requires the subclass to have populated the nonTerminalInfo map defining head rules per nonterminal category; if it is null the head finder is unconfigured and IllegalStateException is thrown. It catches subclasses that never initialized their grammar-specific rules.","triggerScenarios":"Instantiating a subclass of AbstractCollinsHeadFinder whose constructor did not create and fill nonTerminalInfo (e.g. writing a custom head finder without defining rules), then calling determineHead / percolateHeads.","commonSituations":"Custom head finder implementations for a new treebank or language that forgot rule definitions; subclasses constructed via reflection where the initializing constructor was bypassed.","solutions":["Initialize nonTerminalInfo = new HashMap<>() in the subclass constructor and populate rules for every relevant nonterminal category (percolate default rules via super)","Reuse an existing configured head finder (e.g. CollinsHeadFinder, SemanticHeadFinder) instead of a bare subclass","Add a unit test that calls determineHead on a small tree to fail fast at construction time","If subclassing, call a shared init method from every constructor"],"exampleFix":"// before\npublic MyHeadFinder(TreebankLanguagePack tlp) {\n  super(tlp);\n}\n// after\npublic MyHeadFinder(TreebankLanguagePack tlp) {\n  super(tlp);\n  nonTerminalInfo = new HashMap<>();\n  nonTerminalInfo.put(\"S\", new String[][] {{\"left\", \"NP\", \"VP\"}});\n  nonTerminalInfo.put(\"default\", new String[][] {{\"right\", \"NN\"}});\n}","handlingStrategy":"validation","validationCode":"Field f = AbstractCollinsHeadFinder.class.getDeclaredField(\"nonTerminalInfo\"); f.setAccessible(true); if (f.get(headFinder) == null) { throw new IllegalStateException(\"head finder not initialized\"); }","typeGuard":"boolean isConfigured(HeadFinder hf) { return hf instanceof AbstractCollinsHeadFinder && nonTerminalInfoInitialized((AbstractCollinsHeadFinder) hf); }","tryCatchPattern":"try { Tree head = headFinder.determineHead(tree); } catch (IllegalStateException e) { log.error(\"head finder subclass missing nonTerminalInfo rules\"); }","preventionTips":["Populate nonTerminalInfo in every constructor of a custom head finder","Prefer extending/configured built-ins like CollinsHeadFinder or SemanticHeadFinder","Add a smoke test that determines heads of a sample tree at startup"],"tags":["java","head-finder","initialization"],"backgroundTag":"missing-configuration","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"}