stanfordnlp/CoreNLP · error · RuntimeException

Could not find a valid edge to remove

Error message

Could not find a valid edge to remove

What it means

Util.cleanTree repeatedly deletes nodes from a dependency graph while keeping it a tree; for each removal it picks the best candidate edge to keep (toKeep) and verifies the removal via verifyRemoval. If no verified edge can be removed and there is no fallback (original == null), it throws RuntimeException "Could not find a valid edge to remove" — the graph cannot be reduced to a well-formed tree under the given constraints.

Solutions

  1. Verify the input graph passes isTree()/isDag() checks before calling cleanTree
  2. Inspect the graph for cycles or protected edges blocking all removals and fix the parse
  3. Provide/ensure the original edge fallback path so cleanTree can backtrack instead of throwing

Example fix

// before
Util.cleanTree(graph);
// after
if (!SemgraphicUtil.isTree(graph)) { /* fix or skip */ }
Util.cleanTree(graph);
Defensive patterns

Strategy: validation

Validate before calling

if (!SemgraphicUtil.isTree(tree) || SemgraphicUtil.isCyclic(tree)) { /* repair or skip before cleanTree */ }

Try / catch

try { Util.cleanTree(tree); } catch (RuntimeException e) { /* skip sentence or rebuild graph */ }

Prevention

When it happens

Trigger: Calling Util.cleanTree on a SemanticGraph where every candidate removal fails verifyRemoval (e.g. edges whose relations are conj/subj/obj protected patterns) and no original edge is cached — typically an ill-formed or cyclic input graph that is not actually a tree.

Common situations: Feeding parser output containing cycles or re-entrancies into natural-login openie preprocessing; universal-Dependencies graphs with enhanced/collapsed edges; malformed conllu input.

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


AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10). Data as JSON: /api/errors/3de756827bae4a1c. Report an issue: GitHub.

Appendix: source

Thrown at src/edu/stanford/nlp/naturalli/Util.java:278

            //                                   "\n  Next edge found: " + candidate);
          } else {
            // either or both could be wrong, so we don't try to
            // figure out which to keep
            original = candidate;
          }
        }
        if (toKeep == null) {
          toKeep = candidate;
        } else if (toKeep.getRelation().toString().startsWith("conj") && candidate.getRelation().toString().matches(".subj.*|.obj.*")) {
          toKeep = candidate;
        } else if (!candidate.isExtra() &&
                   !(candidate.getRelation().toString().startsWith("conj") && toKeep.getRelation().toString().matches(".subj.*|.obj.*"))) {
          toKeep = candidate;
        }
      }
      if (!verifyRemoval(tree, incomingEdges, toKeep, toKeep.getDependent())) {
        if (original == null) {
          throw new RuntimeException("Could not find a valid edge to remove");
        }
        toKeep = original;
      }
      List<SemanticGraphEdge> removeEdges = new ArrayList<>();
      for (SemanticGraphEdge candidate : incomingEdges) {
        if (candidate != toKeep) {
          removeEdges.add(candidate);
        }
      }
      removeEdges.forEach(tree::removeEdge);
      extraEdges.addAll(removeEdges);
    }

    // Add apposition edges (simple coref)
    for (SemanticGraphEdge extraEdge : new ArrayList<>(extraEdges)) {  // note[gabor] prevent concurrent modification exception
      for (SemanticGraphEdge candidateAppos : tree.incomingEdgeIterable(extraEdge.getDependent())) {
        if (candidateAppos.getRelation().toString().equals("appos")) {
          extraEdges.add(new SemanticGraphEdge(extraEdge.getGovernor(), candidateAppos.getGovernor(), extraEdge.getRelation(), extraEdge.getWeight(), extraEdge.isExtra()));

View on GitHub (pinned to 1b7edd19c4)