pinpoint-apm/pinpoint · error · IllegalStateException

Cyclic include detected for :

Error message

Cyclic include detected for : 

What it means

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.

Source

Thrown at hbase/hbase-schema/src/main/java/com/navercorp/pinpoint/hbase/schema/reader/xml/XmlParseContext.java:54

    private final Map<String, ChangeSet> changeSetMap = new LinkedHashMap<>();

    private final Set<Resource> visitedResources = new HashSet<>();

    private Resource resource;

    XmlParseContext(Resource resource) {
        this.resource = Objects.requireNonNull(resource, "resource");
    }

    Resource getResource() {
        return resource;
    }

    void setResource(Resource resource) {
        this.resource = Objects.requireNonNull(resource, "resource");
        if (visitedResources.contains(resource)) {
            throw new IllegalStateException("Cyclic include detected for : " + resource);
        }
        visitedResources.add(resource);
    }

    void addChangeSets(Collection<ChangeSet> changeSets) {
        if (CollectionUtils.isEmpty(changeSets)) {
            return;
        }
        for (ChangeSet changeSet : changeSets) {
            String changeSetId = changeSet.getId();
            ChangeSet previous = changeSetMap.put(changeSetId, changeSet);
            if (previous != null) {
                throw new IllegalStateException("Duplicate changeSet found. Id: " + changeSetId);
            }
        }
    }

    List<ChangeSet> getChangeSets() {

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Inspect the resource chain (from the message and stack trace) and remove the include that closes the cycle
  2. Remove the self-include if a file includes itself
  3. Restructure shared definitions into a common file included exactly once per branch
  4. If a file legitimately needs to be included in multiple places, ensure it is not re-included within its own subtree

Example fix

// before (a.xml)
<include file="b.xml"/>  <!-- and b.xml includes a.xml -->
// after (b.xml)
<!-- remove the include of a.xml -->
Defensive patterns

Strategy: try-catch

Validate before calling

// detect cycles before loading by tracking includes yourself
Set<String> seen = new HashSet<>();
for (String include : collectIncludes(rootXml)) {
    if (!seen.add(include)) throw new IllegalStateException("cycle at " + include);
}

Try / catch

try {
    schemaReader.loadChangeSets(resource);
} catch (IllegalStateException e) {
    if (e.getMessage().startsWith("Cyclic include detected")) {
        // fix the include chain in the offending XML file
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Schema XML file A includes file B, and B (directly or transitively) includes A again; loadChangeSets then calls setResource with a Resource already visited.

Common situations: 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).

Related errors


AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/d491d0fe8b14e227. Report an issue: GitHub.