{"record":{"id":"642339e1ddda640f","repo":"stanfordnlp/CoreNLP","slug":"no-head-rule-defined-for","errorCode":null,"errorMessage":"No head rule defined for ","messagePattern":"No head rule defined for ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/trees/AbstractCollinsHeadFinder.java","lineNumber":245,"sourceCode":"    if (how == null) {\n      if (DEBUG) {\n        log.info(\"Warning: No rule found for \" + motherCat +\n                           \" (first char: \" + motherCat.charAt(0) + ')');\n        log.info(\"Known nonterms are: \" + nonTerminalInfo.keySet());\n      }\n      if (defaultRule != null) {\n        if (DEBUG) {\n          log.info(\"  Using defaultRule\");\n        }\n        return traverseLocate(kids, defaultRule, true);\n      } else {\n        // TreePrint because TreeGraphNode only prints the node number,\n        // doesn't print the tree structure\n        TreePrint printer = new TreePrint(\"penn\");\n        StringWriter buffer = new StringWriter();\n        printer.printTree(t, new PrintWriter(buffer));\n        // TODO: we could get really fancy and define our own exception class to represent this\n        throw new IllegalArgumentException(\"No head rule defined for \" + motherCat + \" using \" + this.getClass() + \" in \" + buffer);\n      }\n    }\n    for (int i = 0; i < how.length; i++) {\n      boolean lastResort = (i == how.length - 1);\n      theHead = traverseLocate(kids, how[i], lastResort);\n      if (theHead != null) {\n        break;\n      }\n    }\n    if (DEBUG) {\n      log.info(\"  Chose \" + (theHead == null ? \"null node\": theHead.label()));\n    }\n    return theHead;\n  }\n\n  /**\n   * Attempt to locate head daughter tree from among daughters.\n   * Go through daughterTrees looking for things from or not in a set given by","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/trees/AbstractCollinsHeadFinder.java#L227-L263","documentation":"determineNonTrivialHead looks up a head rule for the node's category (motherCat) in the nonTerminalInfo map. If no rule exists for that category the finder cannot know which child is the head and throws, including the class name and a printed tree so the missing rule can be identified. Subclasses of AbstractCollinsHeadFinder must define rules for every non-terminal they will encounter.","triggerScenarios":"Calling determineHead on a tree containing a category (motherCat) for which the head finder subclass registered no entry in nonTerminalInfo — e.g. a custom POS tag, a projected/edited node, or a category introduced by preprocessing.","commonSituations":"Using EnglishHeadFinder/semanticHeadFinder rules on non-English or non-PTB treebank data; custom tree transformations inserting new node labels (e.g. X, ARTIFICAL nodes); missing tgrep/label normalization causing uppercase/mismatched categories.","solutions":["Add a rule for the missing category in your head finder subclass's nonTerminalInfo map (or extend a subclass that already has it).","Use a head finder matching your treebank (e.g. UniversalSemanticHeadFinder for non-English data).","Normalize/strip categories before head lookup, or configure the treebank language pack so node values match the rule keys.","Inspect the printed tree in the message to see the exact category and context that lacked a rule."],"exampleFix":"// before (custom finder)\nnonTerminalInfo = new HashMap<>();\nnonTerminalInfo.put(\"S\", new String[][]{{\"left\", \"VP\"}});\n// after — add rule for the unhandled category\nnonTerminalInfo.put(\"S\", new String[][]{{\"left\", \"VP\"}});\nnonTerminalInfo.put(\"SBAR\", new String[][]{{\"left\", \"IN\", \"SBAR\"}});","handlingStrategy":"validation","validationCode":"if (headFinder instanceof AbstractCollinsHeadFinder) { /* verify nonTerminalInfo covers your categories, or pre-check */ Set<String> cats = collectCategories(tree); assert rulesCover(cats); }","typeGuard":null,"tryCatchPattern":"try { head = hf.determineHead(t, parent); } catch (IllegalArgumentException e) { log.warn(\"No head rule for tree: {}\", e.getMessage()); head = t.children()[0]; /* fallback: leftmost child */ }","preventionTips":["Register head rules for every category your treebank can produce","Use the language-appropriate head finder subclass","Log unknown categories and extend nonTerminalInfo proactively"],"tags":["java","nlp","parsing","missing-config"],"backgroundTag":"missing-config-value","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"}