stanfordnlp/CoreNLP · error · IllegalArgumentException

Tree never finished! Offending proto

Error message

Tree never finished!  Offending proto: ${proto}

What it means

After consuming all nodes of a FlattenedParseTree proto, fromProtoFlattenedTree checks that a completed root tree ('finished') exists. If the nodes list ended with unclosed Open nodes, the tree was never completed, so an IllegalArgumentException naming the proto is thrown.

Solutions

  1. Regenerate the proto with toFlattenedTree, which balances every Open with a Close.
  2. Check Open/Close balance (count equality and non-empty stack at end) before deserializing.
  3. Catch IllegalArgumentException, log the corrupt annotation, and re-parse the sentence.

Example fix

// before
nodes = [open(), label("ROOT"), open(), label("NP"), close()]; // NP closed but ROOT never closed
// after
nodes = [open(), label("ROOT"), open(), label("NP"), close(), close()];
Defensive patterns

Strategy: validation

Validate before calling

int depth = 0;
for (var n : proto.getNodesList()) {
  if (n.hasOpenNode()) depth++;
  else if (n.hasCloseNode()) depth--;
}
if (depth != 0) throw new IllegalArgumentException("unbalanced Open/Close nodes (ends at depth " + depth + ")");

Try / catch

try {
  tree = ProtobufAnnotationSerializer.fromProto(proto);
} catch (IllegalArgumentException e) {
  log.warn("Tree never finished (truncated proto?): " + e.getMessage());
  tree = null;
}

Prevention

When it happens

Trigger: Deserializing a FlattenedParseTree proto whose nodes list has more Open markers than Close markers — e.g. truncated protos, or builders that forgot the final root closeNode.

Common situations: Network truncation or partial writes of serialized annotations; custom serializers that never emit the last Close for the root.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


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

Appendix: source

Thrown at src/edu/stanford/nlp/pipeline/ProtobufAnnotationSerializer.java:2271

          if (next.hasScore()) {
            top.setScore(next.getScore());
          }
        } else {
          // subsequence labels will be children
          LabeledScoredTreeNode child = new LabeledScoredTreeNode();
          CoreLabel value = new CoreLabel();
          value.setCategory(next.getValue());
          value.setValue(next.getValue());
          child.setLabel(value);
          top.addChild(child);
          if (next.hasScore()) {
            child.setScore(next.getScore());
          }
        }
      }
    }
    if (finished == null) {
      throw new IllegalArgumentException("Tree never finished!  Offending proto: " + proto);
    }
    return finished;
  }

  /**
   * Retrieve a Tree object and then attach the tokens passed in.
   *
   * Useful for keeping the tokens in the tree synchronized with the tokens in a sentence.
   */
  public static Tree fromProto(CoreNLPProtos.ParseTree proto, List<CoreLabel> tokens) {
    Tree tree = fromProto(proto);
    Trees.setLeafLabels(tree, tokens);
    return tree;
  }

  /**
   * Retrieve a Tree object from a saved protobuf.
   * This is not intended to be used on its own, but it is safe (lossless) to do so and therefore it is

View on GitHub (pinned to 1b7edd19c4)