{"record":{"id":"f9c5205a7cd86375","repo":"stanfordnlp/CoreNLP","slug":"internal-error-annotators-have-a-circular-depend","errorCode":null,"errorMessage":"[INTERNAL ERROR] Annotators have a circular dependency.","messagePattern":"\\[INTERNAL ERROR\\] Annotators have a circular dependency\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/pipeline/StanfordCoreNLP.java","lineNumber":505,"sourceCode":"    Set<String> unorderedAnnotators = new LinkedHashSet<>();  // linked to preserve order\n    Collections.addAll(unorderedAnnotators, annotators);\n    for (String annotator : annotators) {\n      // Add the annotator\n      if (!getNamedAnnotators().containsKey(annotator.toLowerCase())) {\n        throw new IllegalArgumentException(\"Unknown annotator: \" + annotator);\n      }\n\n      // Add its transitive dependencies\n      unorderedAnnotators.add(annotator.toLowerCase());\n      if (!Annotator.DEFAULT_REQUIREMENTS.containsKey(annotator.toLowerCase())) {\n        throw new IllegalArgumentException(\"Cannot infer requirements for annotator: \" + annotator);\n      }\n      Queue<String> fringe = new LinkedList<>(Annotator.DEFAULT_REQUIREMENTS.get(annotator.toLowerCase()));\n      int ticks = 0;\n      while (!fringe.isEmpty()) {\n        ticks += 1;\n        if (ticks == 1000000) {\n          throw new IllegalStateException(\"[INTERNAL ERROR] Annotators have a circular dependency.\");\n        }\n        String prereq = fringe.poll();\n        unorderedAnnotators.add(prereq);\n        fringe.addAll(Annotator.DEFAULT_REQUIREMENTS.get(prereq.toLowerCase()));\n      }\n    }\n\n    if (useParseForPos) {\n      unorderedAnnotators.remove(Annotator.STANFORD_POS);\n    }\n\n    // Order the annotators\n    List<String> orderedAnnotators = new ArrayList<>();\n    while (!unorderedAnnotators.isEmpty()) {\n      boolean somethingAdded = false;  // to make sure the dependencies are satisfiable\n      // Loop over candidate annotators to add\n      Iterator<String> iter = unorderedAnnotators.iterator();\n      while (iter.hasNext()) {","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/pipeline/StanfordCoreNLP.java#L487-L523","documentation":"During transitive prerequisite expansion, ensurePrerequisiteAnnotators uses a tick counter as an infinite-loop guard; if the fringe has not emptied after ~1,000,000 iterations it concludes the annotator requirement graph contains a cycle and throws IllegalStateException.","triggerScenarios":"Annotator A requires B and B (transitively) requires A in Annotator.DEFAULT_REQUIREMENTS - normally only reachable with custom requirement definitions or corrupted/patched requirement maps.","commonSituations":"Custom requirement overrides creating a cycle; bugs after modifying DEFAULT_REQUIREMENTS programmatically; extremely large chains misinterpreted as cycles (rare).","solutions":["Inspect and fix the requirement definitions so the dependency graph is acyclic.","Remove custom requirements modifications and revert to stock DEFAULT_REQUIREMENTS.","Reduce the annotator list to built-ins and re-add custom ones incrementally to isolate the cycle.","Report/patch the cycle in the requirements map if using a forked CoreNLP."],"exampleFix":"// before\nDEFAULT_REQUIREMENTS.put(\"a\", asList(\"b\"));\nDEFAULT_REQUIREMENTS.put(\"b\", asList(\"a\")); // cycle\n// after\nDEFAULT_REQUIREMENTS.put(\"a\", asList(\"b\"));\nDEFAULT_REQUIREMENTS.put(\"b\", Collections.emptyList());","handlingStrategy":"try-catch","validationCode":"// Detect cycles in requirement map before building pipeline\nMap<String,Set<String>> g = new HashMap<>();\nAnnotator.DEFAULT_REQUIREMENTS.forEach((k,v) -> g.put(k, new HashSet<>(v)));\n// topological sort / DFS color-marking to find a cycle","typeGuard":null,"tryCatchPattern":"try { pipeline = new StanfordCoreNLP(props); } catch (IllegalStateException e) { if (e.getMessage().contains(\"circular dependency\")) { resetRequirementOverrides(); pipeline = new StanfordCoreNLP(props); } else throw e; }","preventionTips":["Never create reciprocal entries in DEFAULT_REQUIREMENTS.","Keep requirement overrides in one reviewed place.","Add a unit test that topologically sorts the requirement graph."],"tags":["java","internal-error","circular-dependency","annotators"],"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"}