{"record":{"id":"3d38fae59bf3d68c","repo":"stanfordnlp/CoreNLP","slug":"error-looking-for-a-non-existent-parent-in-tree","errorCode":null,"errorMessage":"Error: looking for a non-existent parent in tree \" + tree + \" for \\\"\" + toString() + '\"","messagePattern":"Error: looking for a non-existent parent in tree \" \\+ tree \\+ \" for \\\\\"\" \\+ toString\\(\\) \\+ '\"","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/trees/tregex/tsurgeon/TreeLocation.java","lineNumber":62,"sourceCode":"      this.coindexer = coindexer;\n\n      this.childMatcher = child.matcher(newNodeNames, coindexer);\n    }\n\n    Pair<Tree,Integer> evaluate(Tree tree, TregexMatcher tregex) {\n      int newIndex; // initialized below\n      Tree parent; // initialized below\n      Tree relativeNode = childMatcher.evaluate(tree, tregex);\n      Matcher m = daughterPattern.matcher(relation);\n      if (m.matches()) {\n        newIndex = Integer.parseInt(m.group(1))-1;\n        parent = relativeNode;\n        if(relation.charAt(1)=='-') // backwards.\n          newIndex = parent.children().length - newIndex;\n      } else {\n        parent = relativeNode.parent(tree);\n        if (parent == null) {\n          throw new RuntimeException(\"Error: looking for a non-existent parent in tree \" + tree + \" for \\\"\" + toString() + '\"');\n        }\n        int index = parent.objectIndexOf(relativeNode);\n        switch(relation) {\n          case \"$+\" :\n            newIndex = index;\n            break;\n          case \"$-\" :\n            newIndex = index+1;\n            break;\n          default :\n            throw new RuntimeException(\"Error: Haven't dealt with relation \" + relation + \" yet.\");\n        }\n      }\n      return new Pair<>(parent, newIndex);\n    }\n  }\n\n  @Override","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/trees/tregex/tsurgeon/TreeLocation.java#L44-L80","documentation":"Tsurgeon's location-parsing step in TreeLocation.evaluate computes the parent node under which an insertion/relocation index will be applied. When the relative node named by a $+ / $- (right/left sister) relation has no parent in the tree — i.e. it is the root, or it was detached by a prior operation — the library cannot compute an insertion point and throws this RuntimeException.","triggerScenarios":"A tsurgeon operation uses $+ or $- whose target node is the root of the matched tree, or a node deleted/pruned by an earlier operation in the same sequence, so relativeNode.parent(tree) returns null in evaluate.","commonSituations":"Writing an adjoin/insert operation that anchors on the root with $+/$-; running multi-operation tsurgeon scripts where an earlier delete/prune removes the ancestor the later operation references; applying patterns to single-node trees where the anchor has no sisters.","solutions":["Check that the node referenced by $+/$- is not the root and has a parent in the tree","Reorder tsurgeon operations so deletes/prunes that remove the anchor run after the $+/$- operation","Use a relation that does not require a parent (e.g. anchor on a sibling node instead)","Wrap processPatternsOnTree in try-catch for RuntimeException and skip trees that fail"],"exampleFix":"// before\nTsurgeon.processPatternsOnTree(new Pair<>(tregex, parseOperation(\"insert (NP foo) >0 $+root\")), tree);\n// after\n// anchor on a non-root node instead: insert relative to a sister of the target\nTsurgeon.processPatternsOnTree(new Pair<>(tregex, parseOperation(\"insert (NP foo) >0 $-NP\")), tree);","handlingStrategy":"try-catch","validationCode":"// before applying ops: ensure anchor node is not the root\nprivate static boolean hasParentAnchors(TregexMatcher m, Tree root) {\n  return m.getMatch() != root;\n}","typeGuard":"if (relativeNode == null || relativeNode.parent(tree) == null) { skipOperation(); return; }","tryCatchPattern":"try {\n  Tsurgeon.processPatternsOnTree(op, tree);\n} catch (RuntimeException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"non-existent parent\")) { logSkip(tree); }\n  else throw e;\n}","preventionTips":["Never anchor $+/$- relations on the root node","Order operations so deletions happen after relational insertions","Verify tregex named captures match non-root nodes","Test tsurgeon scripts on single-node edge-case trees"],"tags":["tregex","tsurgeon","tree-manipulation","runtime-exception"],"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"}