bumptech/glide · error · IllegalStateException
Cannot call evictOnWorkThread on thread: {}
Error message
Cannot call evictOnWorkThread on thread: {} What it means
Thrown by the SQL journal disk cache's EvictionManager.evictOnWorkThread() when invoked from a thread whose Looper is not the dedicated work Looper. Eviction touches the SQLite journal and must be serialized on the single work thread to avoid corruption.
Source
Thrown at integration/sqljournaldiskcache/src/main/java/com/bumptech/glide/integration/sqljournaldiskcache/EvictionManager.java:100
* cache size.
*/
void maybeScheduleEviction() {
maybeScheduleEviction(getMaximumSizeBytes());
}
private void maybeScheduleEviction(long maximumSizeBytes) {
if (isEvictionRequired(maximumSizeBytes)) {
evictionHandler.obtainMessage(MessageIds.EVICT).sendToTarget();
}
}
private boolean isEvictionRequired(long maximumSizeBytes) {
return journal.getCurrentSizeBytes() > evictionSlopBytes + maximumSizeBytes;
}
private void evictOnWorkThread() {
if (!Looper.myLooper().equals(workLooper)) {
throw new IllegalStateException(
"Cannot call evictOnWorkThread on thread: " + Thread.currentThread().getName());
}
long maximumSizeBytes = getMaximumSizeBytes();
long staleDateMs = clock.currentTimeMillis() - staleEvictionThresholdMs;
List<String> staleEntriesKeys = journal.getStaleEntries(staleDateMs);
// Writes may queue up a number of eviction messages. After the first one runs, eviction may no
// longer be necessary, so we simply ignore the message.
if (!isEvictionRequired(maximumSizeBytes) && staleEntriesKeys.isEmpty()) {
if (LOG_VERBOSE) {
Log.v(TAG, "Ignoring eviction, not needed");
}
return;
}
if (LOG_DEBUG) {
Log.d(TAG, "Starting eviction on work thread");
}
int successfullyDeletedCount = 0;View on GitHub (pinned to eb14a895d8)
Solutions
- Use the public disk-cache API; never call EvictionManager methods directly.
- If testing, run assertions on the work thread (e.g. via the work-thread Handler.post) or use the provided test helpers.
- Ensure you did not obtain or share the EvictionManager across components that post to a different Looper.
- Report a bug if the error appears during ordinary library usage, since eviction should always be internally scheduled.
Example fix
// before (wrong thread) evictionManager.evictOnWorkThread() // called from main thread // after (let the library schedule it) diskCache.put(key, data) // internally posts eviction to the work thread
Defensive patterns
Strategy: validation
Validate before calling
// Only schedule eviction through the public API on the work thread.
if (Looper.myLooper() == workLooper) {
evictionManager.evictOnWorkThread()
} else {
error("Eviction must run on the work thread")
} Prevention
- Never call EvictionManager internals directly; use the disk-cache public API.
- In tests, post work to the work-thread Handler.
- Keep a single EvictionManager per cache directory.
When it happens
Trigger: evictOnWorkThread() runs and Looper.myLooper() does not equal workLooper. Normally eviction is posted as a Message to the work-thread Handler; this fires only if eviction is invoked directly from the wrong thread.
Common situations: Calling an internal/eviction method directly instead of through the public API; a misconfigured Handler in a test; reflection invoking evictOnWorkThread off-thread. In normal library use this should not occur because eviction is always posted to the work Handler.
Related errors
- Cannot run recovery on a thread other than the work thread!
- Failed to find entries to evict.
- Size mismatch, expected to be able to evict at least {} byte
- Failed to delete entry, key: {}, size: {}, actually deleted:
- Failed to create cache directory: {}
AI-assisted analysis of bumptech/glide@eb14a895d8 (2026-08-14).
Data as JSON: /api/errors/acb3a0652994a251.
Report an issue: GitHub.