bumptech/glide · error · IllegalStateException

You cannot auto lock an already locked options object, try…

Error message

You cannot auto lock an already locked options object, try clone() first

What it means

Thrown by BaseRequestOptions.autoClone() when the options object is already locked (isLocked == true) but auto-clone has not yet been enabled. autoClone() turns a locked object into an auto-cloning one so that subsequent mutations transparently return clones, but you cannot retroactively flip this state on a plain-locked object because the caller may already hold a reference expecting immutability.

Solutions

  1. Call autoClone() on a fresh, unlocked clone: requestOptions.clone().autoClone()
  2. Enable autoClone before the object ever gets locked (i.e. before it is applied to any request)
  3. Avoid sharing a single mutable RequestOptions across many requests; build a new one per use or freeze a template and clone from it
  4. Use RequestOptions.diskCacheStrategyOf(...) / factory-style helpers which return independent immutable instances

Example fix

// before
val shared = RequestOptions().centerCrop()
Glide.with(ctx).load(url).apply(shared).into(iv) // apply may lock shared
shared.autoClone() // IllegalStateException

// after
val template = RequestOptions().centerCrop()
val perRequest = template.clone().autoClone()
Glide.with(ctx).load(url).apply(perRequest).into(iv)
Defensive patterns

Strategy: validation

Validate before calling

fun RequestOptions.autoCloneSafe(): RequestOptions =
  if (isLocked) clone().autoClone() else autoClone()

Prevention

When it happens

Trigger: Calling RequestOptions.lock() followed by RequestOptions.autoClone() on the same instance. lock() is applied internally by Glide when options are applied to a request (e.g. into()), so reusing the same RequestOptions builder across multiple loads and then calling autoClone() triggers it.

Common situations: Library/SDK authors building a shared RequestOptions singleton, calling apply() (which locks) and later autoClone(); calling autoClone() on options returned from Glide.init or from an already-built request.

Related errors


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

Appendix: source

Thrown at library/src/main/java/com/bumptech/glide/request/BaseRequestOptions.java:1303

  @SuppressWarnings("unchecked")
  public T lock() {
    isLocked = true;
    // This is the only place we should not check locked.
    return self();
  }

  /**
   * Similar to {@link #lock()} except that mutations cause a {@link #clone()} operation to happen
   * before the mutation resulting in all methods returning a new Object and leaving the original
   * locked object unmodified.
   *
   * <p>Auto clone is not retained by cloned objects returned from mutations. The cloned objects are
   * mutable and are not locked.
   */
  @NonNull
  public T autoClone() {
    if (isLocked && !isAutoCloneEnabled) {
      throw new IllegalStateException(
          "You cannot auto lock an already locked options object" + ", try clone() first");
    }
    isAutoCloneEnabled = true;
    return lock();
  }

  @NonNull
  @SuppressWarnings("unchecked")
  protected final T selfOrThrowIfLocked() {
    if (isLocked) {
      throw new IllegalStateException("You cannot modify locked T, consider clone()");
    }
    return self();
  }

  protected final boolean isAutoCloneEnabled() {
    return isAutoCloneEnabled;
  }

View on GitHub (pinned to eb14a895d8)