stanfordnlp/CoreNLP · error · TsurgeonRuntimeException
Attempted to replace a root node with more than one node…
Error message
Attempted to replace a root node with more than one node, unable to proceed
What it means
ReplaceNode.evaluate replaces the matched node with new children. When the matched node is the root of the whole tree, the replacement must yield exactly one root; if more than one replacement node was supplied, the operation cannot attach multiple roots and throws TsurgeonRuntimeException.
Solutions
- Make the tregex pattern match only non-root nodes (e.g. require a parent: "@NP < __" or exclude ROOT).
- Supply exactly one replacement node if the pattern may match the root.
- Catch TsurgeonRuntimeException and skip/adjust the match when replacing roots with multiple nodes is intended to be disallowed.
Example fix
// before tregex: "@ROOT" ; replace: =root /S/ /NP/ // multi-node replace on root // after tregex: "@ROOT <1=child" ; replace: =child /S/ // replace a non-root child, single node
Defensive patterns
Strategy: try-catch
Validate before calling
// only allow multi-node replacements for non-root matches
boolean safeReplace(String tregex, int replacementCount) {
boolean matchesRoot = tregex.contains("ROOT") || !tregex.contains("<");
return !(matchesRoot && replacementCount > 1);
} Try / catch
try {
tree = op.evaluate(tree, matcher);
} catch (TsurgeonRuntimeException e) {
if (e.getMessage().contains("replace a root node")) {
log.warn("Skipping root replacement: " + e.getMessage());
} else throw e;
} Prevention
- Write tregex patterns that exclude the root when using multi-node replace.
- Limit replacement lists to a single node unless the match is guaranteed non-root.
- Run scripts over a sample corpus first to detect accidental root matches.
When it happens
Trigger: A replace Tsurgeon operation (replace <match> <node1> <node2> ...) where the tregex match binds the root node (oldNode == tree) and the replacement list contains more than two entries (children.length > 2, i.e. more than one replacement node).
Common situations: Writing 'replace =root X Y' style Tsurgeon scripts; patterns that unintentionally match the root (e.g. bare tree-level labels like "ROOT" or "@S" matching the top node); reusing a multi-node replacement script against patterns that also hit roots.
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
- Error -- no foot node found for " + originalTreeString
- Error -- two foot nodes in subtree" + t.toString()
- No foot node found for " + auxTree
- Parents did not match for trees when applied to " + this
- Node name " + name + " does not exist in the searched tree
AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10).
Data as JSON: /api/errors/ca20fc6387756459.
Report an issue: GitHub.
Appendix: source
Thrown at src/edu/stanford/nlp/trees/tregex/tsurgeon/ReplaceNode.java:41
private static final Function<AuxiliaryTree, HoldTreeNode> convertAuxiliaryToHold = t -> new HoldTreeNode(t);
@Override
public TsurgeonMatcher matcher(Map<String,Tree> newNodeNames, CoindexationGenerator coindexer) {
return new Matcher(newNodeNames, coindexer);
}
private class Matcher extends TsurgeonMatcher {
public Matcher(Map<String,Tree> newNodeNames, CoindexationGenerator coindexer) {
super(ReplaceNode.this, newNodeNames, coindexer);
}
@Override
public Tree evaluate(Tree tree, TregexMatcher tregex) {
Tree oldNode = childMatcher[0].evaluate(tree, tregex);
if (oldNode==tree) {
if (children.length > 2) {
throw new TsurgeonRuntimeException("Attempted to replace a root node with more than one node, unable to proceed");
}
return childMatcher[1].evaluate(tree, tregex);
}
Tree parent = oldNode.parent(tree);
int i = parent.objectIndexOf(oldNode);
parent.removeChild(i);
for (int j = 1; j < children.length; ++j) {
Tree newNode = childMatcher[j].evaluate(tree, tregex);
parent.insertDtr(newNode.deepCopy(), i + j - 1);
}
return tree;
}
}
}
View on GitHub (pinned to 1b7edd19c4)