bumptech/glide · error · IllegalStateException

You cannot use a request as both the main request and a thum

Error message

You cannot use a request as both the main request and a thumbnail, consider using clone() on the request(s) passed to thumbnail()

What it means

When building a request that includes a thumbnail sub-request via thumbnail(RequestBuilder), Glide checks the isThumbnailBuilt flag to detect when the same RequestBuilder instance is used for both the main request and the thumbnail. This creates an infinite recursion because building the thumbnail triggers building the main request again. The IllegalStateException advises calling clone() so the thumbnail gets its own independent request builder.

Source

Thrown at library/src/main/java/com/bumptech/glide/RequestBuilder.java:1255

    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }

  private Request buildThumbnailRequestRecursive(
      Object requestLock,
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      BaseRequestOptions<?> requestOptions,
      Executor callbackExecutor) {
    if (thumbnailBuilder != null) {
      // Recursive case: contains a potentially recursive thumbnail request builder.
      if (isThumbnailBuilt) {
        throw new IllegalStateException(
            "You cannot use a request as both the main request and a "
                + "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
      }

      TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
          thumbnailBuilder.transitionOptions;

      // Apply our transition by default to thumbnail requests but avoid overriding custom options
      // that may have been applied on the thumbnail request explicitly.
      if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
        thumbTransitionOptions = transitionOptions;
      }

      Priority thumbPriority =
          thumbnailBuilder.isPrioritySet()
              ? thumbnailBuilder.getPriority()
              : getThumbnailPriority(priority);

View on GitHub (pinned to eb14a895d8)

Solutions

  1. Call clone() on the builder before passing it to thumbnail(): builder.thumbnail(builder.clone())
  2. Create two separate RequestBuilder instances: one for the main image and one for the thumbnail
  3. For same-URL thumbnails, prefer the thumbnail(float) overload which does not have this problem

Example fix

// before
RequestBuilder<Drawable> b = Glide.with(this).load(url);
b.thumbnail(b).into(imageView);
// after
RequestBuilder<Drawable> b = Glide.with(this).load(url);
b.thumbnail(b.clone()).into(imageView);
Defensive patterns

Strategy: type-guard

Type guard

// Always clone() the builder before passing it as a thumbnail
RequestBuilder<Drawable> main = Glide.with(context).load(url);
RequestBuilder<Drawable> thumb = main.clone(); // independent copy
main.thumbnail(thumb).into(imageView);

Prevention

When it happens

Trigger: Calling requestBuilder.thumbnail(requestBuilder) using the same object for both. Assigning a RequestBuilder to a variable, using it for into(), and also passing it to thumbnail() on itself or a sibling that shares state.

Common situations: Building a request with a low-res thumbnail from the same URL: storing one RequestBuilder and passing it to both into and thumbnail. DRY-minded code that tries to reuse a single builder instance for multiple purposes.

Related errors


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