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
- Validate the dependency tree before extraction (each node has one governor, no cycles) — e.g. run a cycle check over the governor map.
- Regenerate the parse with the default Stanford neural dependency parser / standard pipeline instead of custom or merged parses.
- Check for preprocessing code that mutates the SemanticGraph (removing nodes, re-attaching edges) and could create a cycle.
- 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
- Validate dependency graphs for cycles before relation extraction
- Do not merge or hand-edit governor links across sentences
- Re-parse third-party/converted input instead of trusting its dependency annotation
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
- Expected labels to have indices
- mapDependencies: HeadFinder failed!
- mapDependencies: need HeadFinder
- No GrammaticalStructureFactory (typed dependencies)…
- after W derivative, index() != x.length()
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)