Tencent/matrix · warning · IllegalStateException
Could not find weak reference with key
Error message
Could not find weak reference with key
What it means
After finding DestroyedActivityInfo instances, the analyzer matches each instance's activity reference key against the requested key to locate the corresponding weak reference's referent. If every key candidate differs from the target key, no matching weak reference exists in the dump and it throws IllegalStateException listing all keys found.
Solutions
- Re-capture the hprof immediately after the leak watch triggers so the weak reference is still present.
- Verify the key passed to findLeakingReference matches the key used when the activity was destroyed (same key-generation logic/version).
- Treat this as 'no leak — object was GC'd' and return a no-leak result instead of throwing.
- Make sure the analyzed dump belongs to the same session that recorded the destroyed activity.
Example fix
// before
throw new IllegalStateException("Could not find weak reference with key " + key + " in " + keysFound);
// after
if (keysFound.isEmpty()) {
return null; // weak ref already cleared: not a leak
}
throw new IllegalStateException("Could not find weak reference with key " + key + " in " + keysFound); Defensive patterns
Strategy: try-catch
Validate before calling
// ensure the key was recorded when the activity was destroyed; verify dump session matches
Try / catch
try { referent = findLeakingReference(key, snapshot); } catch (IllegalStateException e) { return ActivityLeakResult.noLeak(); /* weak ref likely cleared */ } Prevention
- Capture the hprof immediately when leak detection fires
- Use stable, version-consistent key generation
- Verify dump session matches the session that recorded the key
When it happens
Trigger: findLeakingReference is called with a key that was never registered in the heap dump — the activity was already GC'd (its weak reference cleared), the key was computed differently at capture vs. analysis time, or the analyzed dump corresponds to a different session.
Common situations: Analyzing a stale heap dump after the weakly-referenced activity was collected; key generation (UUID/activity name) changed between app versions; re-running analysis with a wrong key; the leak was a false alarm and GC reclaimed the activity.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Unabled to find destroy activity info class with name:
- Unsupported reference type $value
- Unsupported object type $value
- free space($freeSpace) less than $CLEAN_THRESHOLD, skip…
- closer == null
AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08).
Data as JSON: /api/errors/c5644b3188be0a9f.
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/ActivityLeakAnalyzer.java:106
if (infoClass == null) {
throw new IllegalStateException("Unabled to find destroy activity info class with name: "
+ DESTROYED_ACTIVITY_INFO_CLASSNAME);
}
List<String> keysFound = new ArrayList<>();
for (Instance infoInstance : infoClass.getInstancesList()) {
final List<ClassInstance.FieldValue> values = classInstanceValues(infoInstance);
final String keyCandidate = asString(fieldValue(values, ACTIVITY_REFERENCE_KEY_FIELDNAME));
if (keyCandidate.equals(key)) {
final Instance weakRefObj = fieldValue(values, ACTIVITY_REFERENCE_FIELDNAME);
if (weakRefObj == null) {
continue;
}
final List<ClassInstance.FieldValue> activityRefs = classInstanceValues(weakRefObj);
return fieldValue(activityRefs, "referent");
}
keysFound.add(keyCandidate);
}
throw new IllegalStateException(
"Could not find weak reference with key " + key + " in " + keysFound);
}
private ActivityLeakResult findLeakTrace(long analysisStartNanoTime, Snapshot snapshot,
Instance leakingRef) {
ShortestPathFinder pathFinder = new ShortestPathFinder(mExcludedRefs);
ShortestPathFinder.Result result = pathFinder.findPath(snapshot, leakingRef);
// False alarm, no strong reference path to GC Roots.
if (result.referenceChainHead == null) {
return ActivityLeakResult.noLeak(AnalyzeUtil.since(analysisStartNanoTime));
}
final ReferenceChain referenceChain = result.buildReferenceChain();
final String className = leakingRef.getClassObj().getClassName();
if (result.excludingKnown || referenceChain.isEmpty()) {
return ActivityLeakResult.noLeak(AnalyzeUtil.since(analysisStartNanoTime));View on GitHub (pinned to 3b8293bd65)