stanfordnlp/CoreNLP · error · IllegalArgumentException

Required a tree with CoreLabels

Error message

Required a tree with CoreLabels

What it means

SentimentPipeline.setSentimentLabels recursively annotates a tree with predicted sentiment classes and requires every node's Label to be an instance of CoreLabel. If any node carries a plain StringLabel/LabeledWord or another Label implementation, the cast would be unsafe, so an IllegalArgumentException is thrown instead. This is an input precondition failure: the tree given to the pipeline is not backed by the expected label type.

Solutions

  1. Ensure the input trees go through a pipeline (StanfordCoreNLP tokenize/parse) that produces CoreLabel-backed nodes before sentiment labeling.
  2. If reading trees from text, re-label them, e.g. with a TreeNormalizer/TreeTransformer that replaces each node label with a CoreLabel carrying the same value.
  3. Check which TreeReader/parser model was used; switch to one configured with CoreLabel factory (e.g. via ParserOptions/parser props).
  4. As a last resort, convert labels manually: clone the tree and for each node setLabel(new CoreLabel()) copying the original value before calling the pipeline.

Example fix

// before
Tree t = Tree.valueOf("(ROOT (S (NP I) (VP (V like) (NP it))))");
SentimentPipeline.setSentimentLabels(t); // StringLabel nodes -> IllegalArgumentException

// after
Tree read = treeReader.readTree(...); // reader configured with CoreLabel factory
// or rebuild labels:
for (Tree node : t) {
  CoreLabel cl = new CoreLabel();
  cl.setValue(node.label().value());
  node.setLabel(cl);
}
Defensive patterns

Strategy: type-guard

Validate before calling

boolean hasCoreLabels(Tree t) {
  for (Tree node : t) {
    if (!(node.label() instanceof CoreLabel)) return false;
  }
  return true;
}
// call before pipeline: if (!hasCoreLabels(tree)) rebuildLabels(tree);

Type guard

static boolean isCoreLabelTree(Tree t) {
  if (t == null || !(t.label() instanceof CoreLabel)) return false;
  for (Tree child : t.children()) {
    if (!isCoreLabelTree(child)) return false;
  }
  return true;
}

Try / catch

try {
  SentimentPipeline.setSentimentLabels(tree);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("CoreLabels")) {
    tree = relabelAsCoreLabels(tree); // fallback conversion
    SentimentPipeline.setSentimentLabels(tree);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling setSentimentLabels (directly or via outputTree in SentimentPipeline) with a Tree whose nodes were built by a parser or TreeReader that produces StringLabel or other non-CoreLabel Label implementations instead of CoreLabel.

Common situations: Loading trees from a plain-text .mrg/.tree file with a generic TreeReader; combining trees produced by an older parser setup with the sentiment model; programmatically constructing trees with Tree.valueOf() without forcing CoreLabel backing; swapping tokenizer/parser props so downstream trees lose CoreLabel annotation.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

Thrown at src/edu/stanford/nlp/sentiment/SentimentPipeline.java:81

  private SentimentPipeline() {} // static methods

  /**
   * Sets the labels on the tree (except the leaves) to be the integer
   * value of the sentiment prediction.  Makes it easy to print out
   * with Tree.toString()
   */
  private static void setSentimentLabels(Tree tree) {
    if (tree.isLeaf()) {
      return;
    }

    for (Tree child : tree.children()) {
      setSentimentLabels(child);
    }

    Label label = tree.label();
    if (!(label instanceof CoreLabel)) {
      throw new IllegalArgumentException("Required a tree with CoreLabels");
    }
    CoreLabel cl = (CoreLabel) label;
    cl.setValue(Integer.toString(RNNCoreAnnotations.getPredictedClass(tree)));
  }

  /**
   * Sets the labels on the tree to be the indices of the nodes.
   * Starts counting at the root and does a postorder traversal.
   */
  private static int setIndexLabels(Tree tree, int index) {
    if (tree.isLeaf()) {
      return index;
    }

    tree.label().setValue(Integer.toString(index));
    index++;
    for (Tree child : tree.children()) {
      index = setIndexLabels(child, index);

View on GitHub (pinned to 1b7edd19c4)