stanfordnlp/CoreNLP · error · TsurgeonParseException
Error -- two foot nodes in subtree" + t.toString()
Error message
Error -- two foot nodes in subtree" + t.toString()
What it means
findFootNodeHelper recursively scans an auxiliary tree for the foot node. If more than one node in the subtree carries the foot marker, the scan finds two candidate descendants and throws TsurgeonParseException, because a foot node must be unique.
Solutions
- Ensure exactly one node label in the auxiliary tree contains the '@' foot marker.
- Scan the aux tree string for occurrences of '@' and remove all but the intended attachment-point marker.
- Note '@' is also an escape character in labels; if a literal '@' is needed in a label, escape it (see escapedFootNodeCharacter handling) so it is not counted as a foot.
Example fix
// before
String aux = "{@SBAR {@NP the dog}}"; // two foot markers
// after
String aux = "{@SBAR {NP the dog}}"; // exactly one foot node Defensive patterns
Strategy: validation
Validate before calling
int countFootMarkers(String auxTreeString) {
int count = 0;
for (char c : auxTreeString.toCharArray()) if (c == '@') count++;
return count; // must be exactly 1 for a valid auxiliary tree
} Try / catch
try {
AuxiliaryTree aux = new AuxiliaryTree(tree, true);
} catch (TsurgeonParseException e) {
if (e.getMessage().contains("two foot nodes")) throw new IllegalArgumentException("Aux tree has multiple '@' markers: " + tree);
throw e;
} Prevention
- Audit aux tree strings for duplicate '@' characters before running Tsurgeon.
- Escape literal '@' intended as label content so it is not read as a foot marker.
- Write unit tests that construct each auxiliary tree used in production scripts.
When it happens
Trigger: Constructing an AuxiliaryTree whose tree labels contain the '@' foot escape on two or more nodes, e.g. '{@NP {@PP ...}}'; findFootNode calls this helper and the second found node triggers the throw.
Common situations: Hand-written Tsurgeon auxiliary trees where '@' was accidentally duplicated (e.g. applied to both a category label and a value, or copy-pasted to nested nodes); automated generation of aux trees marking every node.
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
- No foot node found for " + auxTree
- Attempted to replace a root node with more than one node…
- 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/d8a1503cea85754b.
Report an issue: GitHub.
Appendix: source
Thrown at src/edu/stanford/nlp/trees/tregex/tsurgeon/AuxiliaryTree.java:162
return result;
}
private static Tree findFootNodeHelper(Tree t) {
Tree foundDtr = null;
if (t.isLeaf()) {
Matcher m = footNodeLabelPattern.matcher(t.label().value());
if (m.matches()) {
t.label().setValue(m.group(1));
return t;
} else {
return null;
}
}
for (Tree child : t.children()) {
Tree thisFoundDtr = findFootNodeHelper(child);
if (thisFoundDtr != null) {
if (foundDtr != null) {
throw new TsurgeonParseException("Error -- two foot nodes in subtree" + t.toString());
} else {
foundDtr = thisFoundDtr;
}
}
}
Matcher m = escapedFootNodeCharacter.matcher(t.label().value());
t.label().setValue(m.replaceAll(footNodeCharacter));
return foundDtr;
}
/* ******************************************************* *
* below here is init stuff for getting node -> names maps *
* ******************************************************* */
// There are two ways in which you can can match the start of a name
// expression.
// The first is if you have any number of non-escaping charactersView on GitHub (pinned to 1b7edd19c4)