stanfordnlp/CoreNLP · warning

Likely cycle in relation tree

Error message

Likely cycle in relation tree

What it means

Warning logged by RelationTriple.relationHead when walking the dependency tree upward to find the head of a relation took 100 or more iterations without terminating. This almost always means the dependency graph (as stored in the Semgrex/governor map used here) contains a cycle, so the "guess" never converges; the method logs the warning and returns whatever guess it has.

Solutions

  1. Validate the dependency tree before extraction (each node has one governor, no cycles) — e.g. run a cycle check over the governor map.
  2. Regenerate the parse with the default Stanford neural dependency parser / standard pipeline instead of custom or merged parses.
  3. Check for preprocessing code that mutates the SemanticGraph (removing nodes, re-attaching edges) and could create a cycle.
  4. If inputs are third-party, sanitize: rebuild a tree from the tokens and re-parse rather than trusting the incoming graph.

Example fix

// before: trust any graph
SemanticGraph g = readGraphFromConll(line);
Triple t = extractor.apply(g);
// after: sanity-check acyclicity first
SemanticGraph g = readGraphFromConll(line);
if (!isAcyclic(g)) { g = parse(sentence); } // re-parse malformed input
Defensive patterns

Strategy: validation

Validate before calling

boolean isAcyclic(SemanticGraph g) {
  for (IndexedWord root : g.getRoots()) {
    java.util.Set<IndexedWord> seen = new java.util.HashSet<>();
    java.util.Deque<IndexedWord> stack = new java.util.ArrayDeque<>(java.util.Collections.singletonList(root));
    while (!stack.isEmpty()) {
      IndexedWord w = stack.pop();
      if (!seen.add(w)) return false;
      g.getChildList(w).forEach(stack::push);
    }
  }
  return true;
}

Try / catch

try { triple = relationHead(node, graph); } catch (Throwable t) { log.warn("relationHead failed on suspect graph; re-parsing sentence"); }

Prevention

When it happens

Trigger: Calling relationHead (e.g. via RelationTriple extraction / KBP / OpenIE) on a dependency tree whose governor links form a cycle, so the loop `while (...) { guess = governor.get(guess) }` exceeds iters >= 100 at RelationTriple.java:605.

Common situations: Feeding malformed or corrupted dependency parses (e.g. from a broken custom parser or badly converted CoNLL input) into the relation extractor; combining subtrees from different sentences; bugs in custom Semgrex/dependency post-processing that create governor cycles.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/edu/stanford/nlp/ie/util/RelationTriple.java:605

      if (relation.size() == 1) { return relation.get(0); }
      CoreLabel guess = null;
      CoreLabel newGuess = super.relationHead();
      int iters = 0;  // make sure we don't infinite loop...
      while (guess != newGuess && iters < 100) {
        guess = newGuess;
        iters += 1;
        for (SemanticGraphEdge edge : sourceTree.incomingEdgeIterable(new IndexedWord(guess))) {
          // find a node in the relation list which is a governor of the candidate root
          Optional<CoreLabel> governor = relation.stream().filter(x -> x.index() == edge.getGovernor().index()).findFirst();
          // if we found one, this is the new root. The for loop continues
          if (governor.isPresent()) {
            newGuess = governor.get();
          }
        }
      }
      // Return
      if (iters >= 100) {
        err("Likely cycle in relation tree");
      }
      return guess;
    }

    /** {@inheritDoc} */
    @Override
    public Optional<SemanticGraph> asDependencyTree() {
      return Optional.of(sourceTree);
    }
  }


  /**
   * A {@link edu.stanford.nlp.ie.util.RelationTriple}, but with both the tree and the entity
   * links saved as well.
   */
  public static class WithLink extends WithTree {
    /** The canonical entity link of the subject */

View on GitHub (pinned to 1b7edd19c4)