{"record":{"id":"95538d1e31b25a99","repo":"stanfordnlp/CoreNLP","slug":"between-when-the-outgoing-edge-was-found-and-now","errorCode":null,"errorMessage":"Between when the outgoing edge was found and now, the edge was somehow deleted","messagePattern":"Between when the outgoing edge was found and now, the edge was somehow deleted","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/SetPhraseHead.java","lineNumber":128,"sourceCode":"      // the newHead should be the root now\n      Set<IndexedWord> roots = new HashSet<>(sg.getRoots());\n      if (!roots.contains(newHead)) {\n        modified = true;\n        for (IndexedWord other : matchedNodes) {\n          roots.remove(other);\n        }\n        roots.add(newHead);\n      }\n      sg.setRoots(roots);\n    } else if (edgeOut.getTarget() != newHead) {\n      SemanticGraphEdge newEdge = new SemanticGraphEdge(edgeOut.getSource(),\n                                                        newHead,\n                                                        edgeOut.getRelation(),\n                                                        edgeOut.getWeight(),\n                                                        edgeOut.isExtra());\n      boolean success = sg.removeEdge(edgeOut);\n      if (!success) {\n        throw new RuntimeException(\"Between when the outgoing edge was found and now, the edge was somehow deleted\");\n      }\n      sg.addEdge(newEdge);\n      modified = true;\n    }\n\n    for (SemanticGraphEdge edge : relocateEdges) {\n      SemanticGraphEdge newEdge = new SemanticGraphEdge(newHead,\n                                                        edge.getTarget(),\n                                                        edge.getRelation(),\n                                                        edge.getWeight(),\n                                                        edge.isExtra());\n      boolean success = sg.removeEdge(edge);\n      if (!success) {\n        throw new RuntimeException(\"Between when the incoming edge was found and now, the edge was somehow deleted\");\n      }\n      sg.addEdge(newEdge);\n      modified = true;\n    }","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/semgraph/semgrex/ssurgeon/SetPhraseHead.java#L110-L146","documentation":"SetPhraseHead.evaluate() first locates the outgoing edge from the old head, rebuilds it with a new target, and calls SemanticGraph.removeEdge(). If removeEdge returns false, the edge it just found is no longer present in the graph, so the ssurgeon rule aborts with this RuntimeException. It is an internal consistency check: within a single evaluate() pass no other code should have removed the edge.","triggerScenarios":"Calling SetPhraseHead.evaluate(sg, sm) where the SemanticGraph is mutated between edge discovery (findEdge/edge lookup) and removeEdge, or where the edge object reference does not match an edge still in the graph (e.g. duplicate evaluation over a graph that was already rewritten, or a custom graph implementation whose removeEdge fails).","commonSituations":"Applying the same ssurgeon operation twice to a graph without re-matching; running custom Ssurgeon edits that remove edges inside other operations sharing the same SemanticGraph; passing a SemanticGraph copy whose edge identity differs from the matched one.","solutions":["Re-run the semgrex match on the current graph immediately before applying SetPhraseHead so the edge references are fresh","Ensure only one ssurgeon operation mutates the graph at a time; do not remove edges concurrently or between lookup and removal","Check for duplicated application of the same Ssurgeon rule (idempotence) and guard with a 'modified' flag before re-running","If using a custom SemanticGraph subclass, verify removeEdge correctly matches edges by identity/equality"],"exampleFix":"// before: edge collected in an earlier pass\nfor (SemanticGraphEdge e : oldEdges) { sg.removeEdge(e); }\n// after: re-locate the edge on the live graph before removing\nSemanticGraphEdge edgeOut = sg.getEdge(oldHead, target, reln);\nif (edgeOut != null) sg.removeEdge(edgeOut);","handlingStrategy":"try-catch","validationCode":"// before evaluate: verify the edge still exists\nSemanticGraphEdge e = sg.getEdge(oldHead, target, reln);\nif (e == null) { reRunSemgrexMatch(sg); }","typeGuard":null,"tryCatchPattern":"try { op.evaluate(sg, sm); } catch (RuntimeException e) { if (e.getMessage().contains(\"edge was somehow deleted\")) { sm = pattern.matcher(sg); /* rematch and retry once */ } else { throw e; } }","preventionTips":["Re-run semgrex matching immediately before each mutating ssurgeon operation","Apply each Ssurgeon rule to a graph only once (idempotence guard)","Deep-copy the SemanticGraph before editing if the original is needed afterwards","Avoid interleaving custom edge removals with Ssurgeon operations on the same graph"],"tags":["ssurgeon","semgraph","invariant"],"backgroundTag":"internal-invariant-violation","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"}