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
- Hop to the main thread before calling into(): withContext(Dispatchers.Main) { Glide.with(...).into(iv) }
- In RxJava, observeOn(AndroidSchedulers.mainThread()) before the subscribe that calls Glide
- Use view.post { Glide.with(view)... } from a background thread
- 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
- Always run into()/clear()/begin()/pause()/resume() on the main thread
- In coroutines use withContext(Dispatchers.Main); in RxJava observeOn(AndroidSchedulers.mainThread())
- From a background callback use view.post { Glide.with(view)... }
- Lint for Glide calls inside IO-thread scopes
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
- You must call this method on a background thread
- You can't start or clear loads in RequestListener or Target
- You cannot start a load on a fragment before it is attached
- Unable to find GlideModule implementation
- Expected instanceof GlideModule, but found: {module}
AI-assisted analysis of bumptech/glide@eb14a895d8 (2026-08-14).
Data as JSON: /api/errors/14b765d9338f5a0d.
Report an issue: GitHub.