stanfordnlp/CoreNLP · error · SsurgeonParseException
Cannot make a MergeNodes out of fewer than 2 nodes (got " +…
Error message
Cannot make a MergeNodes out of fewer than 2 nodes (got " + argsBox.nodes.size() + ")
What it means
Ssurgeon's parseEditLine builds a MergeNodes edit from a semgrex ssurgeon resource line. A MergeNodes operation merges two or more matched nodes into one, so the parser requires at least 2 -node entries on the edit line. If fewer are given, it throws SsurgeonParseException before constructing the edit.
Solutions
- Add at least two -node:NAME arguments naming nodes matched by the semgrex query
- Verify the node names exist in the preceding semgrex pattern so they are captured in argsBox
- If you truly operate on one node, use a different edit (e.g. relabel-node, lemmatize) instead of merge-grams
Example fix
# before
ssurgeon: { dog } :: merge-grams -node:dog
# after
ssurgeon: { dog & dep(gov,dog) } :: merge-grams -node:dog -node:gov Defensive patterns
Strategy: validation
Validate before calling
// before parsing, verify the merge line has >= 2 -node args
boolean validMerge(String line) {
return line.startsWith("merge-grams") &&
line.split("-node:", -1).length - 1 >= 2;
} Try / catch
try {
SsurgeonEdit e = Ssurgeon.parseEditLine(line);
} catch (SsurgeonParseException ex) {
log.severe("Bad merge-grams rule: " + line + " -> " + ex.getMessage());
} Prevention
- Count -node: occurrences in each merge-grams line before shipping rule files
- Validate ssurgeon rule files in CI by parsing them with parseEditLine
- Use a different single-node edit when the rule only touches one node
When it happens
Trigger: An ssurgeon edit line like 'merge-grams -node:foo' with only one -node argument (or none) is parsed via Ssurgeon.parseEditLine; argsBox.nodes.size() < 2 throws.
Common situations: Hand-written ssurgeon rule files where the author forgot the second -node, or a rule generator emitted a merge with only one node (e.g. after filtering removed a node name).
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
- Cannot make a KillAllIncomingEdges out of " +…
- Error in SsurgeonEdit.parseEditLine: command '"+command+"'…
- Found both regex and exact in the splits for splitWord
- Unable to process Ssurgeon edit line: " + editLine
- Attempt to create ChineseSimWordAvgDepGrammar before…
AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10).
Data as JSON: /api/errors/94a10acd36318014.
Report an issue: GitHub.
Appendix: source
Thrown at src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/Ssurgeon.java:651
return new DeleteGraphFromNode(argsBox.nodes.get(0));
} else if (command.equalsIgnoreCase(DeleteLeaf.LABEL)) {
if (argsBox.nodes.size() != 1) {
throw new SsurgeonParseException("Cannot make a DeleteLeaf out of " + argsBox.nodes.size() + " nodes");
}
return new DeleteLeaf(argsBox.nodes.get(0));
} else if (command.equalsIgnoreCase(EditNode.LABEL)) {
if (argsBox.nodes.size() != 1) {
throw new SsurgeonParseException("Cannot make an EditNode out of " + argsBox.nodes.size() + " nodes. Please use exactly one -node");
}
return new EditNode(argsBox.nodes.get(0), argsBox.annotations, argsBox.updateMorphoFeatures, argsBox.remove, argsBox.removeMorphoFeatures);
} else if (command.equalsIgnoreCase(Lemmatize.LABEL)) {
if (argsBox.nodes.size() != 1) {
throw new SsurgeonParseException("Cannot make a Lemmatize out of " + argsBox.nodes.size() + " nodes. Please use exactly one -node");
}
return new Lemmatize(argsBox.nodes.get(0), language);
} else if (command.equalsIgnoreCase(MergeNodes.LABEL)) {
if (argsBox.nodes.size() < 2) {
throw new SsurgeonParseException("Cannot make a MergeNodes out of fewer than 2 nodes (got " + argsBox.nodes.size() + ")");
}
return new MergeNodes(argsBox.nodes, argsBox.annotations);
} else if (command.equalsIgnoreCase(RelabelNamedEdge.LABEL)) {
if (argsBox.reln == null) {
throw new SsurgeonParseException("Relation not specified for AddEdge");
}
GrammaticalRelation reln = GrammaticalRelation.valueOf(language, argsBox.reln);
return new RelabelNamedEdge(argsBox.edge, reln);
} else if (command.equalsIgnoreCase(RemoveEdge.LABEL)) {
GrammaticalRelation reln = null;
if (argsBox.reln != null) {
reln = GrammaticalRelation.valueOf(argsBox.reln);
}
return new RemoveEdge(reln, argsBox.govNodeName, argsBox.dep);
} else if (command.equalsIgnoreCase(RemoveNamedEdge.LABEL)) {
return new RemoveNamedEdge(argsBox.edge);
} else if (command.equalsIgnoreCase(KillAllIncomingEdges.LABEL)) {
if (argsBox.nodes.size() != 1) {View on GitHub (pinned to 1b7edd19c4)