stanfordnlp/CoreNLP · error · IllegalArgumentException

mapDependencies: need HeadFinder

Error message

mapDependencies: need HeadFinder

What it means

mapDependencies() requires a HeadFinder to compute which child of each node is the head when building dependencies. Passing null is rejected immediately with this IllegalArgumentException rather than failing later deep in the traversal.

Solutions

  1. Pass a concrete HeadFinder instance, e.g. new CollinsHeadFinder() or UniversalSemanticHeadFinder
  2. Null-check or assert the HeadFinder before calling mapDependencies
  3. Trace where the null comes from (a factory/config lookup returning null) and fix the initialization

Example fix

// before
Set<Dependency<Label,Label,Object>> deps = tree.mapDependencies(f, hf); // hf == null
// after
HeadFinder hf = new UniversalSemanticHeadFinder();
Set<Dependency<Label,Label,Object>> deps = tree.mapDependencies(f, hf);
Defensive patterns

Strategy: type-guard

Validate before calling

Objects.requireNonNull(hf, "mapDependencies requires a HeadFinder");

Type guard

boolean hasHeadFinder(HeadFinder hf) { return hf != null; }

Try / catch

try { deps = tree.mapDependencies(f, hf); } catch (IllegalArgumentException e) { log.error("Missing HeadFinder: {}", e.getMessage()); }

Prevention

When it happens

Trigger: Calling tree.mapDependencies(f, null) — e.g. the HeadFinder variable was never initialized, or a helper method returned null and the result was passed straight through.

Common situations: Refactoring code where the HeadFinder used to be a field that is now null; conditionally constructing a HeadFinder that ends up unset; copy-pasted call sites where the hf argument was dropped.

Related errors


AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10). Data as JSON: /api/errors/2360208367901e39. Report an issue: GitHub.

Appendix: source

Thrown at src/edu/stanford/nlp/trees/Tree.java:1374

  /**
   * Return a set of Label-Label dependencies, represented as
   * Dependency objects, for the Tree.  The Labels are the ones of the leaf
   * nodes of the tree, without mucking with them.
   *
   * @param f  Dependencies are excluded for which the Dependency is not
   *           accepted by the Filter
   * @param hf The HeadFinder to use to identify the head of constituents.
   *           The code assumes
   *           that it can use {@code headPreTerminal(hf)} to find a
   *           tag and word to make a CoreLabel.
   * @return Set of dependencies (each a {@code Dependency} between two
   *           {@code CoreLabel}s, which each contain a tag(), word(),
   *           and value(), the last two of which are identical).
   */
  public Set<Dependency<Label, Label, Object>> mapDependencies(Predicate<Dependency<Label, Label, Object>> f, HeadFinder hf) {
    if (hf == null) {
      throw new IllegalArgumentException("mapDependencies: need HeadFinder");
    }
    Set<Dependency<Label, Label, Object>> deps = Generics.newHashSet();
    for (Tree node : this) {
      if (node.isLeaf() || node.children().length < 2) {
        continue;
      }
      // Label l = node.label();
      // log.info("doing kids of label: " + l);
      //Tree hwt = node.headPreTerminal(hf);
      Tree hwt = node.headTerminal(hf);
      // log.info("have hf, found head preterm: " + hwt);
      if (hwt == null) {
        throw new IllegalStateException("mapDependencies: HeadFinder failed!");
      }

      for (Tree child : node.children()) {
        // Label dl = child.label();
        // Tree dwt = child.headPreTerminal(hf);

View on GitHub (pinned to 1b7edd19c4)