Tencent/matrix · error · IllegalStateException

Found resource cycle!

Error message

Found resource cycle! <visitPath>

What it means

During unused-resource reference resolution, readChildReference() does a DFS over the resource dependency graph and throws IllegalStateException when a resource references another resource already on the current visit path — i.e., a cycle. The message includes the cycle path stack for debugging.

Solutions

  1. Inspect the cycle path in the message and refactor one resource to break the cycle
  2. Exclude the cyclic resources from analysis via the ignore-resources param (PARAM_IGNORE_RESOURCES_LIST)
  3. Update Matrix — newer versions may treat cycles as terminal instead of throwing

Example fix

// gradle param
// before
params: unused-resources without ignore list
// after
params.put(JobConstants.PARAM_IGNORE_RESOURCES_LIST, "drawable/cycle_a,drawable/cycle_b");
Defensive patterns

Strategy: try-catch

Validate before calling

// inspect the reported cycle path in the message before re-running
String msg = e.getMessage(); // "Found resource cycle! [a, b, a]" — add these to ignore list

Try / catch

try {
    TaskResult r = task.call();
} catch (Exception e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Found resource cycle!")) {
        // add cycle members to PARAM_IGNORE_RESOURCES_LIST and retry
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: AAPT/resource definitions where resources reference each other cyclically (e.g., drawable A references drawable B which references A), encountered while recursively decoding resources.

Common situations: Exotic resource setups: vector drawables, drawables with theme attributes, or generated resources with mutual references; also triggered by unusual custom resource merging.

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


AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08). Data as JSON: /api/errors/9bcfde7d76ddc849. Report an issue: GitHub.

Appendix: source

Thrown at matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java:464

        for (String pattern : ignoreSet) {
            if (name.matches(pattern)) {
                return true;
            }
        }
        return false;
    }

    private void readChildReference(String resource) throws IllegalStateException {
        if (nonValueReferences.containsKey(resource)) {
            visitPath.push(resource);
            Set<String> childReference = nonValueReferences.get(resource);
            unusedResSet.removeAll(childReference);
            for (String reference : childReference) {
                if (!visitPath.contains(reference)) {
                    readChildReference(reference);
                } else {
                    visitPath.push(reference);
                    throw new IllegalStateException("Found resource cycle! " + visitPath.toString());
                }
            }
            visitPath.pop();
        }
    }


    @Override
    public TaskResult call() throws TaskExecuteException {
        try {
            TaskResult taskResult = TaskResultFactory.factory(type, TaskResultFactory.TASK_RESULT_TYPE_JSON, config);
            long startTime = System.currentTimeMillis();
            readMappingTxtFile();
            readResourceTxtFile();
            ResguardUtil.readResMappingTxtFile(resMappingTxt, null, resguardMap);
            unusedResSet.addAll(resourceDefMap.values());
            Log.i(TAG, "find resource declarations %d items.", unusedResSet.size());
            decodeCode();

View on GitHub (pinned to 3b8293bd65)