{"record":{"id":"5e881c9468cb0d3c","repo":"didi/DoKit","slug":"could-not-find-weak-reference-with-key-in","errorCode":null,"errorMessage":"Could not find weak reference with key {} in {}","messagePattern":"Could not find weak reference with key (.+?) in (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"Android/dokit-leakcanary/src/main/java/com/squareup/leakcanary/HeapAnalyzer.java","lineNumber":244,"sourceCode":"        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);\n    }\n\n    private AnalysisResult findLeakTrace(long analysisStartNanoTime, Snapshot snapshot,\n                                         Instance leakingRef, boolean computeRetainedSize) {\n\n        listener.onProgressUpdate(AnalyzerProgressListener.Step.FINDING_SHORTEST_PATH);\n        ShortestPathFinder pathFinder = new ShortestPathFinder(excludedRefs);\n        ShortestPathFinder.Result result = pathFinder.findPath(snapshot, leakingRef);\n\n        String className = leakingRef.getClassObj().getClassName();\n\n        // False alarm, no strong reference path to GC Roots.\n        if (result.leakingNode == null) {\n            return AnalysisResult.noLeak(className, since(analysisStartNanoTime));\n        }\n\n        listener.onProgressUpdate(AnalyzerProgressListener.Step.BUILDING_LEAK_TRACE);","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Android/dokit-leakcanary/src/main/java/com/squareup/leakcanary/HeapAnalyzer.java#L226-L262","documentation":"After finding the KeyedWeakReference class, findLeakingReference() scans its instances for one whose 'key' field equals the key passed to checkForLeak. If no instance matches, the watched reference is gone from the heap (already GC'd — which means no leak) or the key is wrong, and it throws IllegalStateException listing all keys it did find.","triggerScenarios":"Calling checkForLeak(heapDumpFile, key) where the weak reference with that key was cleared before the dump: the object was garbage collected (good news — no leak) so the KeyedWeakReference referent is null or the instance was collected. Also when passing a stale/wrong key, or when a heap dump is analyzed twice with a key from a different session.","commonSituations":"Analyzing a heap dump after the leaking object was already reclaimed. Keys mixed up between multiple dumps. Custom integrations that persist keys across app restarts and reuse them against fresh dumps.","solutions":["Treat this exception as 'reference no longer in heap': catch IllegalStateException around checkForLeak and report it as no-leak rather than a crash","Make sure the heap dump is triggered while the KeyedWeakReference is still retained (LeakCanary's own flow retries after GC to avoid exactly this)","Verify the key string passed matches the one used in refWatcher.watch(reference, key)"],"exampleFix":"// before\nAnalysisResult result = heapAnalyzer.checkForLeak(heapDumpFile, key);\n\n// after\nAnalysisResult result;\ntry {\n  result = heapAnalyzer.checkForLeak(heapDumpFile, key);\n} catch (IllegalStateException e) {\n  // weak reference was cleared before dump -> object already GC'd, no leak\n  result = AnalysisResult.noLeak(\"reference cleared\", System.nanoTime());\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { result = heapAnalyzer.checkForLeak(heapDumpFile, key); } catch (IllegalStateException e) { if (e.getMessage().contains(\"Could not find weak reference\")) { result = AnalysisResult.noLeak(...); } else throw e; }","preventionTips":["Trigger the heap dump while the KeyedWeakReference is still retained (retry after GC)","Pass exactly the key used in refWatcher.watch(reference, key)"],"tags":["leakcanary","heap-dump","weak-reference","android","java"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}