apache/druid · error · IllegalStateException
Cache reference is null
Error message
Cache reference is null
What it means
PollingLookup.apply() reads from an internal AtomicReference<CacheRefKeeper> that holds the current cache. When the lookup has been closed (or not yet initialized), the reference is null and the method throws IllegalStateException instead of silently returning null. This is an internal invariant: a live lookup must always have a cache reference.
Source
Thrown at extensions-core/lookups-cached-single/src/main/java/org/apache/druid/server/lookup/PollingLookup.java:119
scheduledExecutorService.shutdown();
}
CacheRefKeeper cacheRefKeeper = refOfCacheKeeper.getAndSet(null);
if (cacheRefKeeper != null) {
cacheRefKeeper.doneWithIt();
}
}
}
@Override
@Nullable
public String apply(@Nullable String key)
{
if (key == null) {
return null;
}
final CacheRefKeeper cacheRefKeeper = refOfCacheKeeper.get();
if (cacheRefKeeper == null) {
throw new ISE("Cache reference is null");
}
final PollingCache cache = cacheRefKeeper.getAndIncrementRef();
try {
if (cache == null) {
// it must've been closed after swapping while I was getting it. Try again.
return this.apply(key);
}
return (String) cache.get(key);
}
finally {
if (cache != null) {
cacheRefKeeper.doneWithIt();
}
}
}
@Override
public List<String> unapply(@Nullable final String value)View on GitHub (pinned to 9b90983fd2)
Solutions
- Refresh lookup configuration so all tasks/brokers have the lookup defined, then retry the query
- Check for concurrent use of the lookup after close() in your code; stop using the lookup once closed
- Upgrade Druid if you hit this during normal lookup swaps (known race windows were fixed over time)
Example fix
// before
String val = pollingLookup.apply(key);
// after
if (!pollingLookup.isOpen()) { return null; }
String val = pollingLookup.apply(key); Defensive patterns
Strategy: try-catch
Validate before calling
if (lookup == null || !lookup.isOpen()) { /* skip or refresh lookup config */ } Type guard
boolean usable(PollingLookup l) { return l != null && l.isOpen(); } Try / catch
try { return lookup.apply(key); } catch (IllegalStateException e) { if (e.getMessage().contains("Cache reference is null")) { return fallbackValue; } throw e; } Prevention
- Don't hold PollingLookup references across lookup config updates
- Check lookup existence in the lookup manager before issuing queries that use it
- Re-fetch lookups from the LookupReferencesManager instead of caching instances
When it happens
Trigger: Calling apply(key) after PollingLookup.close() has been called, or applying a lookup while it is being swapped/replaced during a lookup manager refresh race.
Common situations: A query references a lookup that was just removed or updated through the lookup configuration API; stale query plans holding old lookup objects; concurrent close-and-query during cluster config propagation.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/7cf30523a8668893.
Report an issue: GitHub.