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

  1. Use the public disk-cache API; never call EvictionManager methods directly.
  2. If testing, run assertions on the work thread (e.g. via the work-thread Handler.post) or use the provided test helpers.
  3. Ensure you did not obtain or share the EvictionManager across components that post to a different Looper.
  4. 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

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


AI-assisted analysis of bumptech/glide@eb14a895d8 (2026-08-14). Data as JSON: /api/errors/acb3a0652994a251. Report an issue: GitHub.