{"record":{"id":"d491d0fe8b14e227","repo":"pinpoint-apm/pinpoint","slug":"cyclic-include-detected-for","errorCode":null,"errorMessage":"Cyclic include detected for : ","messagePattern":"Cyclic include detected for : ","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hbase/hbase-schema/src/main/java/com/navercorp/pinpoint/hbase/schema/reader/xml/XmlParseContext.java","lineNumber":54,"sourceCode":"\n    private final Map<String, ChangeSet> changeSetMap = new LinkedHashMap<>();\n\n    private final Set<Resource> visitedResources = new HashSet<>();\n\n    private Resource resource;\n\n    XmlParseContext(Resource resource) {\n        this.resource = Objects.requireNonNull(resource, \"resource\");\n    }\n\n    Resource getResource() {\n        return resource;\n    }\n\n    void setResource(Resource resource) {\n        this.resource = Objects.requireNonNull(resource, \"resource\");\n        if (visitedResources.contains(resource)) {\n            throw new IllegalStateException(\"Cyclic include detected for : \" + resource);\n        }\n        visitedResources.add(resource);\n    }\n\n    void addChangeSets(Collection<ChangeSet> changeSets) {\n        if (CollectionUtils.isEmpty(changeSets)) {\n            return;\n        }\n        for (ChangeSet changeSet : changeSets) {\n            String changeSetId = changeSet.getId();\n            ChangeSet previous = changeSetMap.put(changeSetId, changeSet);\n            if (previous != null) {\n                throw new IllegalStateException(\"Duplicate changeSet found. Id: \" + changeSetId);\n            }\n        }\n    }\n\n    List<ChangeSet> getChangeSets() {","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/hbase/hbase-schema/src/main/java/com/navercorp/pinpoint/hbase/schema/reader/xml/XmlParseContext.java#L36-L72","documentation":"XmlParseContext.setResource detects recursive <include> chains in the schema XML: if the resource being loaded is already in visitedResources, an IllegalStateException is thrown. Without this guard, cyclic includes would loop forever loading the same files.","triggerScenarios":"Schema XML file A includes file B, and B (directly or transitively) includes A again; loadChangeSets then calls setResource with a Resource already visited.","commonSituations":"Copy-pasting include lines so a file includes itself; refactoring schema files and accidentally creating an A->B->A cycle; symlinked resources that resolve to the same file under different paths (if Resource equality matches).","solutions":["Inspect the resource chain (from the message and stack trace) and remove the include that closes the cycle","Remove the self-include if a file includes itself","Restructure shared definitions into a common file included exactly once per branch","If a file legitimately needs to be included in multiple places, ensure it is not re-included within its own subtree"],"exampleFix":"// before (a.xml)\n<include file=\"b.xml\"/>  <!-- and b.xml includes a.xml -->\n// after (b.xml)\n<!-- remove the include of a.xml -->","handlingStrategy":"try-catch","validationCode":"// detect cycles before loading by tracking includes yourself\nSet<String> seen = new HashSet<>();\nfor (String include : collectIncludes(rootXml)) {\n    if (!seen.add(include)) throw new IllegalStateException(\"cycle at \" + include);\n}","typeGuard":null,"tryCatchPattern":"try {\n    schemaReader.loadChangeSets(resource);\n} catch (IllegalStateException e) {\n    if (e.getMessage().startsWith(\"Cyclic include detected\")) {\n        // fix the include chain in the offending XML file\n    } else {\n        throw e;\n    }\n}","preventionTips":["Draw the include graph of schema files and verify it is a DAG","Never include a file within its own subtree","Centralize shared change sets in one file included once per entry point"],"tags":["hbase","xml","cyclic-include","schema"],"backgroundTag":"cyclic-include-detected","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}