bumptech/glide · error · IllegalArgumentException

You must call this method on the main thread

Error message

You must call this method on the main thread

What it means

Thrown by Util.assertMainThread() when the calling code is not on the Android main (UI) thread. Glide's request-triggering APIs (into, clear, begin, pause, resume) must run on the main thread because they touch Views and the lifecycle, and cross-thread access would race with the UI. assertMainThread is invoked at the entry of these methods.

Source

Thrown at library/src/main/java/com/bumptech/glide/util/Util.java:185

  private static Handler getUiThreadHandler() {
    if (mainThreadHandler == null) {
      synchronized (Util.class) {
        if (mainThreadHandler == null) {
          mainThreadHandler = new Handler(Looper.getMainLooper());
        }
      }
    }
    return mainThreadHandler;
  }

  /**
   * Throws an {@link java.lang.IllegalArgumentException} if called on a thread other than the main
   * thread.
   */
  public static void assertMainThread() {
    if (!isOnMainThread()) {
      throw new IllegalArgumentException("You must call this method on the main thread");
    }
  }

  /** Throws an {@link java.lang.IllegalArgumentException} if called on the main thread. */
  public static void assertBackgroundThread() {
    if (!isOnBackgroundThread()) {
      throw new IllegalArgumentException("You must call this method on a background thread");
    }
  }

  /** Returns {@code true} if called on the main thread, {@code false} otherwise. */
  public static boolean isOnMainThread() {
    return Looper.myLooper() == Looper.getMainLooper();
  }

  /** Returns {@code true} if called on a background thread, {@code false} otherwise. */
  public static boolean isOnBackgroundThread() {
    return !isOnMainThread();

View on GitHub (pinned to eb14a895d8)

Solutions

  1. Hop to the main thread before calling into(): withContext(Dispatchers.Main) { Glide.with(...).into(iv) }
  2. In RxJava, observeOn(AndroidSchedulers.mainThread()) before the subscribe that calls Glide
  3. Use view.post { Glide.with(view)... } from a background thread
  4. Keep all request-triggering Glide calls (into/clear/begin/pause/resume) on the UI thread

Example fix

// before
launch(Dispatchers.IO) {
  val url = api.fetchImageUrl()
  Glide.with(ctx).load(url).into(imageView) // throws: not main thread
}

// after
launch(Dispatchers.IO) {
  val url = api.fetchImageUrl()
  withContext(Dispatchers.Main) {
    Glide.with(ctx).load(url).into(imageView)
  }
}
Defensive patterns

Strategy: validation

Validate before calling

fun isMainThread(): Boolean = Looper.myLooper() == Looper.getMainLooper()

if (isMainThread()) {
  Glide.with(ctx).load(url).into(imageView)
} else {
  // hop to main thread first
}

Prevention

When it happens

Trigger: Calling Glide.with(...).load(...).into(view) from a background thread, a Coroutine/Flow on Dispatchers.IO, an RxJava observeOn(Schedulers.io()) chain, an AsyncTask doInBackground, or a network callback thread.

Common situations: Doing network call then directly calling Glide.into in the same callback; coroutines without withContext(Dispatchers.Main); RxJava missing observeOn(AndroidSchedulers.mainThread()); threading bugs in custom decoders.

Related errors


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