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.

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.

Appendix: 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)