{"record":{"id":"5f85eec7ccfc6972","repo":"stanfordnlp/CoreNLP","slug":"likely-cycle-in-relation-tree","errorCode":null,"errorMessage":"Likely cycle in relation tree","messagePattern":"Likely cycle in relation tree","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/edu/stanford/nlp/ie/util/RelationTriple.java","lineNumber":605,"sourceCode":"      if (relation.size() == 1) { return relation.get(0); }\n      CoreLabel guess = null;\n      CoreLabel newGuess = super.relationHead();\n      int iters = 0;  // make sure we don't infinite loop...\n      while (guess != newGuess && iters < 100) {\n        guess = newGuess;\n        iters += 1;\n        for (SemanticGraphEdge edge : sourceTree.incomingEdgeIterable(new IndexedWord(guess))) {\n          // find a node in the relation list which is a governor of the candidate root\n          Optional<CoreLabel> governor = relation.stream().filter(x -> x.index() == edge.getGovernor().index()).findFirst();\n          // if we found one, this is the new root. The for loop continues\n          if (governor.isPresent()) {\n            newGuess = governor.get();\n          }\n        }\n      }\n      // Return\n      if (iters >= 100) {\n        err(\"Likely cycle in relation tree\");\n      }\n      return guess;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public Optional<SemanticGraph> asDependencyTree() {\n      return Optional.of(sourceTree);\n    }\n  }\n\n\n  /**\n   * A {@link edu.stanford.nlp.ie.util.RelationTriple}, but with both the tree and the entity\n   * links saved as well.\n   */\n  public static class WithLink extends WithTree {\n    /** The canonical entity link of the subject */","sourceCodeStart":587,"sourceCodeEnd":623,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/ie/util/RelationTriple.java#L587-L623","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: trust any graph\nSemanticGraph g = readGraphFromConll(line);\nTriple t = extractor.apply(g);\n// after: sanity-check acyclicity first\nSemanticGraph g = readGraphFromConll(line);\nif (!isAcyclic(g)) { g = parse(sentence); } // re-parse malformed input","handlingStrategy":"validation","validationCode":"boolean isAcyclic(SemanticGraph g) {\n  for (IndexedWord root : g.getRoots()) {\n    java.util.Set<IndexedWord> seen = new java.util.HashSet<>();\n    java.util.Deque<IndexedWord> stack = new java.util.ArrayDeque<>(java.util.Collections.singletonList(root));\n    while (!stack.isEmpty()) {\n      IndexedWord w = stack.pop();\n      if (!seen.add(w)) return false;\n      g.getChildList(w).forEach(stack::push);\n    }\n  }\n  return true;\n}","typeGuard":null,"tryCatchPattern":"try { triple = relationHead(node, graph); } catch (Throwable t) { log.warn(\"relationHead failed on suspect graph; re-parsing sentence\"); }","preventionTips":["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"],"tags":["dependencies","openie","cycle","nlp"],"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-17T15:17:12.973Z"}