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
- Regenerate the proto with toFlattenedTree, which balances every Open with a Close.
- Check Open/Close balance (count equality and non-empty stack at end) before deserializing.
- 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
- Verify balanced Open/Close counts before deserializing
- Length-prefix and checksum protos in transit to detect truncation
- Ensure the final Close for the root is always emitted by custom writers
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
- Tree continued after it was already closed! Offending proto
- Tree added a child before a label was added to a node! …
- Tree started with a Close, not an Open! Offending proto
- Tree started with a label, not an Open! Offending proto
- Empty label not supported
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 isView on GitHub (pinned to 1b7edd19c4)