stanfordnlp/CoreNLP · error · IllegalArgumentException

Can only operate on preterminals

Error message

Can only operate on preterminals

What it means

replacePOSTag in FrenchTreeNormalizer rewrites the POS tag of a French tree node using MorphoFeatureSpecification, but it only accepts preterminal (POS-level) nodes whose labels are CoreLabel instances. The library throws IllegalArgumentException immediately when a node of any other shape is passed, because the downstream cast to CoreLabel and tag replacement would otherwise fail or corrupt the tree.

Solutions

  1. Traverse the tree and call normalizePreterminal only on preterminal nodes: check t.isPreTerminal() before invoking it
  2. Ensure the tree's labels are CoreLabel, e.g. build trees with CoreLabel factory or copy labels: label.setFromString(...) on a CoreLabel
  3. Run tree.transform(new FrenchTreeNormalizer(...)) / normalizeWholeTrees so the library itself iterates the correct node types
  4. Log or skip non-preterminal nodes instead of forcing them through the normalizer

Example fix

// before
normalizer.normalizePreterminal(sentenceTree, morpho); // throws: not a preterminal

// after
if (sentenceTree.isPreTerminal()) {
  normalizer.normalizePreterminal(sentenceTree, morpho);
} else {
  for (Tree pre : sentenceTree) {
    if (pre.isPreTerminal()) normalizer.normalizePreterminal(pre, morpho);
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// caller-side check
if (tree == null || !tree.isPreTerminal())
  throw new IllegalArgumentException("normalizePreterminal requires a preterminal tree");

Type guard

static boolean isPreTerminalWithCoreLabel(Tree t) {
  return t != null && t.isPreTerminal() && t.label() instanceof CoreLabel;
}

Try / catch

try {
  normalizer.normalizePreterminal(tree, morpho);
} catch (IllegalArgumentException e) {
  log.warn("Skipping non-preterminal/non-CoreLabel node: " + e.getMessage());
}

Prevention

When it happens

Trigger: Calling replacePOSTag (directly or via normalizePreterminal) with a Tree whose !t.isPreTerminal() — e.g. a full sentence tree, an intermediate constituent like an NP/S, or a leaf word node — instead of a POS-tagged preterminal like (NN chat).

Common situations: Developers running the French morphological normalizer over a whole parsed tree without descending to preterminals first; using a custom TreeLabel or LabeledScoredTreeNode with String labels instead of CoreLabel; loading trees from a parser that doesn't use CoreLabel factories.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/edu/stanford/nlp/trees/international/french/FrenchTreeNormalizer.java:70

      }
    };
  }

  @Override
  public String normalizeTerminal(String terminal) {
    if(terminal == null) return terminal;

    return super.normalizeTerminal(terminal).intern();
  }

  @Override
  public String normalizeNonterminal(String category) {
    return super.normalizeNonterminal(category).intern();
  }

  private static void replacePOSTag(Tree t, MorphoFeatureSpecification morpho) {
    if (!t.isPreTerminal()) {
      throw new IllegalArgumentException("Can only operate on preterminals");
    }

    if (!(t.label() instanceof CoreLabel)) {
      throw new IllegalArgumentException("Only operates on CoreLabels");
    }
    CoreLabel label = (CoreLabel) t.label();

    Tree child = t.children()[0];
    if (!(child.label() instanceof CoreLabel)) {
      throw new IllegalArgumentException("Only operates on CoreLabels");
    }
    CoreLabel childLabel = (CoreLabel) child.label();

    // Morphological Analysis
    String morphStr = childLabel.originalText();
    if (morphStr == null || morphStr.equals("")) {
      morphStr = label.value();
      // POS subcategory

View on GitHub (pinned to 1b7edd19c4)