apache/druid · error · SegmentLoadingException
Stale non-partial cache entry
Error message
Stale non-partial cache entry[%s] at id[%s] on location[%s] blocks partial-load reservation and is currently held; the coordinator's load queue will retry
What it means
When reserving an id for a partial load, SegmentLocalCacheManager may find a stale non-partial (complete) cache entry occupying that id. If it cannot be evicted because it is currently held by another user, eviction fails and this SegmentLoadingException is thrown; the coordinator's load queue will retry the load later.
Solutions
- Wait and let the coordinator's load queue retry once the stale entry's holders release it.
- Drop the complete segment (via coordinator drop rules) so the cache entry is released before applying the partial-load rule.
- Check for long-running queries or leaked references holding the old entry; reduce their lifetime.
- Restart or drop the cache location if the entry is genuinely orphaned yet incorrectly reported as held.
Defensive patterns
Strategy: retry
Validate before calling
// before triggering partial load, check the id is not held as a complete entry
final CacheEntry existing = location.getCacheEntry(segmentId);
if (existing != null && !(existing instanceof PartialSegmentMetadataCacheEntry)) {
LOGGER.warn("Segment %s is cached as complete; drop it before applying partial-load rule", segmentId);
} Type guard
static boolean isStaleNonPartialBlocker(final CacheEntry entry) {
return entry != null && !(entry instanceof PartialSegmentMetadataCacheEntry);
} Try / catch
try {
cacheManager.loadPartial(segment, rule);
} catch (SegmentLoadingException e) {
if (e.getMessage() != null && e.getMessage().contains("blocks partial-load reservation")) {
// transient: wait for holders to release, coordinator will retry with backoff
scheduler.schedule(this::retryLoad, 30, TimeUnit.SECONDS);
} else {
throw e;
}
} Prevention
- Drop complete versions of a segment before applying partial-load rules to the same id.
- Minimize long-held references (open queries/cursors) to segments slated for partial loading.
- Monitor for leaked cache-entry holds; investigate entries never released.
- Let the coordinator's load-queue backoff handle retries instead of immediate re-triggering.
When it happens
Trigger: loadPartial or reapplyRuleFromInfoFile encounters a non-partial CacheEntry at the target id, calls location.removeUnheldWeakEntry, and getCacheEntry still returns a held entry afterward.
Common situations: The same segment id was previously loaded as a complete segment and is still referenced (e.g. by an open query or cursor) when a partial-load rule tries to reserve it; lingering references preventing weak-entry removal.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Asked to load path[ ], but it doesn't exist.
- Could not delete cache file at
- Do not know how to handle file type at
- Do not know how to handle source
- e.getMessage()
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/f25ca7b528902334.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/main/java/org/apache/druid/segment/loading/SegmentLocalCacheManager.java:792
* evicting the stale entry first).
* <p>
* {@link StorageLocation#removeUnheldWeakEntry} is a no-op when the entry is held (in-flight query), so we
* detect via {@link StorageLocation#getCacheEntry} whether eviction actually happened. If not, throw a retryable
* {@link SegmentLoadingException}: the coordinator's load queue retries on the next sync, and by then the query
* should have released the hold and eviction will succeed.
*/
private void evictStaleNonPartialWeakEntry(SegmentId segmentId) throws SegmentLoadingException
{
final SegmentCacheEntryIdentifier id = new SegmentCacheEntryIdentifier(segmentId);
for (StorageLocation location : locations) {
final CacheEntry entry = location.getCacheEntry(id);
if (entry == null || entry instanceof PartialSegmentMetadataCacheEntry) {
continue;
}
location.removeUnheldWeakEntry(id);
final CacheEntry stillThere = location.getCacheEntry(id);
if (stillThere != null) {
throw new SegmentLoadingException(
"Stale non-partial cache entry[%s] at id[%s] on location[%s] blocks partial-load reservation and is "
+ "currently held; the coordinator's load queue will retry",
stillThere.getClass().getSimpleName(),
id,
location.getPath()
);
}
log.info(
"Evicted stale non-partial cache entry[%s] at location[%s] to make room for partial-load rule on "
+ "segment[%s]",
entry.getClass().getSimpleName(),
location.getPath(),
segmentId
);
}
}
/**View on GitHub (pinned to 9b90983fd2)