{"record":{"id":"8da00f4069978e52","repo":"stanfordnlp/CoreNLP","slug":"parents-did-not-match-for-trees-when-applied-to","errorCode":null,"errorMessage":"Parents did not match for trees when applied to \" + this","messagePattern":"Parents did not match for trees when applied to \" \\+ this","errorType":"exception","errorClass":"TsurgeonRuntimeException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/trees/tregex/tsurgeon/CreateSubtreeNode.java","lineNumber":72,"sourceCode":"    public Matcher(Map<String,Tree> newNodeNames, CoindexationGenerator coindexer) {\n      super(CreateSubtreeNode.this, newNodeNames, coindexer);\n    }\n\n    /**\n     * Combines all nodes between start and end into one subtree, then\n     * replaces those nodes with the new subtree in the corresponding\n     * location under parent\n     */\n    @Override\n    public Tree evaluate(Tree tree, TregexMatcher tregex) {\n      Tree startChild = childMatcher[0].evaluate(tree, tregex);\n      Tree endChild = (childMatcher.length == 2) ? childMatcher[1].evaluate(tree, tregex) : startChild;\n\n      Tree parent = startChild.parent(tree);\n\n      // sanity check\n      if (parent != endChild.parent(tree)) {\n        throw new TsurgeonRuntimeException(\"Parents did not match for trees when applied to \" + this);\n      }\n      \n      AuxiliaryTree treeCopy = auxTree.copy(this, tree.treeFactory(), tree.label().labelFactory());\n\n      // Collect all the children of the parent of the node we care\n      // about.  If the child is one of the nodes we care about, or\n      // between those two nodes, we add it to a list of inner children.\n      // When we reach the second endpoint, we turn that list of inner\n      // children into a new node using the newly created label.  All\n      // other children are kept in an outer list, with the new node\n      // added at the appropriate location.\n      List<Tree> children = Generics.newArrayList();\n      List<Tree> innerChildren = Generics.newArrayList();\n      boolean insideSpan = false;\n      for (Tree child : parent.children()) {\n        if (child == startChild || child == endChild) {\n          if (!insideSpan && startChild != endChild) {\n            insideSpan = true;","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/trees/tregex/tsurgeon/CreateSubtreeNode.java#L54-L90","documentation":"CreateSubtreeNode.evaluate inserts the auxiliary tree around a range of child nodes; it first sanity-checks that the start and end matched nodes share the same parent. If the two child matchers resolved to nodes with different parents, the operation would splice an invalid structure, so it throws TsurgeonRuntimeException.","triggerScenarios":"A createSubtree operation with two child specifications (a range 'from...to') where the tregex match binds the two names to nodes under different parents — e.g. names matched at different levels of the tree.","commonSituations":"Tregex patterns that name nodes non-locally (e.g. '=start' matched deep and '=end' matched elsewhere) so a range operation spans different parents; patterns reused across trees where occasionally the two named nodes land in different subtrees.","solutions":["Rewrite the tregex pattern so both named nodes are siblings under a common parent (constrain with dominance/sibling relations).","Restrict the match with additional relations (e.g. '$+' immediate-sibling or same-parent constraints) to guarantee a valid range.","Catch TsurgeonRuntimeException around Tsurgeon.processQueries and log/skip non-conforming matches."],"exampleFix":"// before\nString tregex = \"NP <1 =start <2 =end\"; // if start/end can bind under different parents\n// after\nString tregex = \"@NP <1 =start <: =end\"; // constrain both names within the same parent","handlingStrategy":"try-catch","validationCode":"// ensure both named nodes are under one parent before processing\nboolean sameParent(TregexMatcher m, String n1, String n2, Tree root) {\n  Tree a = m.getNode(n1), b = m.getNode(n2);\n  return a != null && b != null && a.parent(root) == b.parent(root);\n}","typeGuard":null,"tryCatchPattern":"try {\n  Tsurgeon.processPattern(pattern, ops, tree);\n} catch (TsurgeonRuntimeException e) {\n  if (e.getMessage().contains(\"Parents did not match\")) {\n    log.warn(\"Skipping tree: range nodes not siblings: \" + e.getMessage());\n  } else throw e;\n}","preventionTips":["Constrain named captures in tregex so range endpoints are siblings (use sibling/dominance relations).","Test Tsurgeon scripts on a diverse sample of trees before batch processing.","Skip-and-log non-conforming matches rather than letting one bad tree abort the corpus run."],"tags":["tsurgeon","tree-manipulation","internal-invariant"],"backgroundTag":"invalid-state-transition","analyzedSha":"1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a","analyzedAt":"2026-09-10T02:24:07.274Z","contentChangedAt":"2026-09-10T02:24:07.274Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}