{"record":{"id":"18d5bc4a14ada025","repo":"didi/DoKit","slug":"could-not-find-the-class-in-the-heap-dump","errorCode":null,"errorMessage":"Could not find the {} class in the heap dump.","messagePattern":"Could not find the (.+?) class in the heap dump\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"Android/dokit-leakcanary/src/main/java/com/squareup/leakcanary/HeapAnalyzer.java","lineNumber":227,"sourceCode":"\n        // Repopulate snapshot with unique GC roots.\n        gcRoots.clear();\n        uniqueRootMap.forEach(new TObjectProcedure<String>() {\n            @Override\n            public boolean execute(String key) {\n                return gcRoots.add(uniqueRootMap.get(key));\n            }\n        });\n    }\n\n    private String generateRootKey(RootObj root) {\n        return String.format(\"%s@0x%08x\", root.getRootType().getName(), root.getId());\n    }\n\n    private Instance findLeakingReference(String key, Snapshot snapshot) {\n        ClassObj refClass = snapshot.findClass(KeyedWeakReference.class.getName());\n        if (refClass == null) {\n            throw new IllegalStateException(\n                    \"Could not find the \" + KeyedWeakReference.class.getName() + \" class in the heap dump.\");\n        }\n        List<String> keysFound = new ArrayList<>();\n        for (Instance instance : refClass.getInstancesList()) {\n            List<ClassInstance.FieldValue> values = HahaHelper.classInstanceValues(instance);\n            Object keyFieldValue = HahaHelper.fieldValue(values, \"key\");\n            if (keyFieldValue == null) {\n                keysFound.add(null);\n                continue;\n            }\n            String keyCandidate = HahaHelper.asString(keyFieldValue);\n            if (keyCandidate.equals(key)) {\n                return HahaHelper.fieldValue(values, \"referent\");\n            }\n            keysFound.add(keyCandidate);\n        }\n        throw new IllegalStateException(\n                \"Could not find weak reference with key \" + key + \" in \" + keysFound);","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Android/dokit-leakcanary/src/main/java/com/squareup/leakcanary/HeapAnalyzer.java#L209-L245","documentation":"During leak analysis, HeapAnalyzer.findLeakingReference() looks up the com.squareup.leakcanary.KeyedWeakReference class in the parsed snapshot. If the class is absent, no references were ever watched with this LeakCanary instrumentation, so analysis cannot proceed and it throws IllegalStateException.","triggerScenarios":"Calling the analyze path (checkForLeak / findLeakingReference) with a heap dump that was NOT captured by this LeakCanary version — e.g. a manually captured dump (am dumpheap), a dump from an app where the RefWatcher never watched anything (buildAndInstall not called, watcher disabled), or a dump from an incompatible LeakCanary version whose class name differs.","commonSituations":"Feeding arbitrary .hprof files (from Android Studio profiler or bug reports) into LeakCanary's analyzer. Analyzing a dump from a process where leak watching was disabled. ProGuard/R8 renaming the KeyedWeakReference class so snapshot.findClass misses it.","solutions":["Only analyze heap dumps captured by the same LeakCanary installation that watched the references","Verify the watcher is installed (LeakCanary.installedRefWatcher() != null) before triggering analysis","Add ProGuard keep rules for com.squareup.leakcanary.** so KeyedWeakReference survives obfuscation","For arbitrary hprof inspection, use a real heap tool (MAT, Android Studio) instead of LeakCanary's analyzer"],"exampleFix":"// before\nAnalysisResult result = heapAnalyzer.checkForLeak(arbitraryHprofFile, referenceKey);\n\n// after\n// only analyze dumps produced by LeakCanary's own HeapDumper\nif (!heapDumpFile.getName().contains(\"leakcanary\")) {\n  // not a LeakCanary dump; use MAT instead\n}","handlingStrategy":"validation","validationCode":"if (LeakCanary.installedRefWatcher() != null && dumpWasProducedByLeakCanary(heapDumpFile)) { heapAnalyzer.checkForLeak(heapDumpFile, key); }","typeGuard":null,"tryCatchPattern":"try { result = heapAnalyzer.checkForLeak(file, key); } catch (IllegalStateException e) { // not a LeakCanary-captured dump or watcher never installed; use MAT instead }","preventionTips":["Only feed LeakCanary-captured dumps into its analyzer","Never strip LeakCanary classes during obfuscation"],"tags":["leakcanary","heap-dump","class-lookup","android","java"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}