Tencent/matrix · error · UnsupportedOperationException

Unknown root type:

Error message

Unknown root type:

What it means

enqueueGcRoots walks all GC roots in the snapshot and enqueues the recognized types (e.g. NATIVE_STACK, JAVA_STATIC). A root whose RootType is outside the supported set hits the default branch and throws UnsupportedOperationException, because the shortest-path search cannot classify that root.

Solutions

  1. Update Matrix to a version whose enqueueGcRoots handles the new root type.
  2. Re-capture the hprof on a supported OS version.
  3. Add the new RootType to the switch and enqueue it like other roots (or intentionally ignore it).
  4. Pre-validate the dump's root types before running analysis and skip unsupported roots.

Example fix

// before
default:
    throw new UnsupportedOperationException("Unknown root type:" + rootObj.getRootType());
// after
default:
    // ignore unknown root types rather than aborting analysis
    break;
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-scan roots: reject or filter dump if any unsupported RootType appears

Try / catch

try { finder.findPath(...); } catch (UnsupportedOperationException e) { log.warn("unknown GC root type: " + e.getMessage()); }

Prevention

When it happens

Trigger: findPath -> enqueueGcRoots encounters a heap-dump GC root whose RootType (from the hprof ROOT_* records) is not one of the enumerated supported cases — e.g. a dump format with new root kinds this analyzer doesn't handle.

Common situations: Heap dumps from newer ART/JDK versions introducing new GC root tags; dumps produced by tools writing nonstandard root records; older Matrix analyzer parsing newer OS dumps.

Related errors


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

Appendix: source

Thrown at matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-analyzer/src/main/java/com/tencent/matrix/resource/analyzer/utils/ShortestPathFinder.java:337

                case SYSTEM_CLASS:
                case VM_INTERNAL:
                    // A local variable in native code.
                case NATIVE_LOCAL:
                    // A global variable in native code.
                case NATIVE_STATIC:
                    // An object that was referenced from an active thread block.
                case THREAD_BLOCK:
                    // Everything that called the wait() or notify() methods, or that is synchronized.
                case BUSY_MONITOR:
                case NATIVE_MONITOR:
                case REFERENCE_CLEANUP:
                    // Input or output parameters in native code.
                case NATIVE_STACK:
                case JAVA_STATIC:
                    enqueue(null, null, rootObj, null, null);
                    break;
                default:
                    throw new UnsupportedOperationException("Unknown root type:" + rootObj.getRootType());
            }
        }
    }

    private boolean checkSeen(ReferenceNode node) {
        return !visitedSet.add(node.instance);
    }

    private void visitRootObj(ReferenceNode node) {
        RootObj rootObj = (RootObj) node.instance;
        Instance child = rootObj.getReferredInstance();

        if (rootObj.getRootType() == RootType.JAVA_LOCAL) {
            Instance holder = HahaSpy.allocatingThread(rootObj);
            // We switch the parent node with the thread instance that holds
            // the local reference.
            Exclusion exclusion = null;
            if (node.exclusion != null) {

View on GitHub (pinned to 3b8293bd65)