{"record":{"id":"c77f9ca8476bfb21","repo":"apache/druid","slug":"expected-weakreference-got-s","errorCode":null,"errorMessage":"Expected WeakReference, got: %s","messagePattern":"Expected WeakReference, got: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions-core/lookups-cached-global/src/main/java/org/apache/druid/server/lookup/namespace/cache/OnHeapNamespaceExtractionCacheManager.java","lineNumber":141,"sourceCode":"  {\n    if (cache.getCache() instanceof ImmutableLookupMap) {\n      return ((ImmutableLookupMap) cache.getCache()).asLookupExtractor(isOneToOne, cacheKeySupplier);\n    } else {\n      return new MapLookupExtractor(cache.getCache(), isOneToOne) {\n        @Override\n        public byte[] getCacheKey()\n        {\n          return cacheKeySupplier.get();\n        }\n      };\n    }\n  }\n\n  @Override\n  void disposeCache(CacheHandler cacheHandler)\n  {\n    if (!(cacheHandler.id instanceof WeakReference)) {\n      throw new ISE(\"Expected WeakReference, got: %s\", cacheHandler.id);\n    }\n    caches.remove(cacheHandler.id);\n  }\n\n  @Override\n  int cacheCount()\n  {\n    expungeCollectedCaches();\n    return caches.size();\n  }\n\n  @Override\n  void monitor(ServiceEmitter serviceEmitter)\n  {\n    long numEntries = 0;\n    long heapSizeInBytes = 0;\n    expungeCollectedCaches();\n    for (WeakReference<Map<String, String>> cacheRef : caches) {","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/lookups-cached-global/src/main/java/org/apache/druid/server/lookup/namespace/cache/OnHeapNamespaceExtractionCacheManager.java#L123-L159","documentation":"OnHeapNamespaceExtractionCacheManager stores cache ids as WeakReference objects; disposeCache() requires that invariant. If a CacheHandler arrives whose id is not a WeakReference, the manager cannot remove it from its weak-reference collection and throws this ISE, indicating the handler was not created by this manager.","triggerScenarios":"Calling disposeCache(cacheHandler) with a handler whose id is a plain map or foreign id object — typically a handler built for a different cache manager implementation (e.g. off-heap) or manually constructed.","commonSituations":"Mixing cache managers (on-heap manager disposing an off-heap CacheHandler); manually constructing CacheHandler with a raw id; classpath mixing of old/new versions of the lookup extension.","solutions":["Only dispose CacheHandlers obtained from the same CacheScheduler/manager that created them.","Verify the CacheHandler implementation matches the active namespace extraction cache manager.","If constructing handlers in tests, use manager/scheduler factory methods so ids are WeakReferences."],"exampleFix":"// before\nCacheHandler h = new CacheHandler(scheduler, someMap, id); // raw id\nonHeapManager.disposeCache(h); // ISE\n// after\nEntry e = scheduler.schedule(namespace);\nscheduler.delete(e); // proper lifecycle, correct id type","handlingStrategy":"type-guard","validationCode":"if (!(cacheHandler.id instanceof WeakReference)) { throw new IllegalArgumentException(\"handler not created by on-heap manager\"); }","typeGuard":"boolean disposable(CacheHandler h) { return h.id instanceof WeakReference; }","tryCatchPattern":"try { manager.disposeCache(handler); } catch (IllegalStateException e) { if (e.getMessage().startsWith(\"Expected WeakReference\")) { /* wrong manager; dispose via originating scheduler */ } else { throw e; } }","preventionTips":["Dispose handlers via the scheduler/manager that created them","Never construct CacheHandler manually with a raw id","Keep lookup extension versions consistent across the cluster"],"tags":["lookup-cache","type-mismatch","lifecycle"],"backgroundTag":"internal-invariant-violation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}