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
- Call autoClone() on a fresh, unlocked clone: requestOptions.clone().autoClone()
- Enable autoClone before the object ever gets locked (i.e. before it is applied to any request)
- Avoid sharing a single mutable RequestOptions across many requests; build a new one per use or freeze a template and clone from it
- 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
- Call autoClone() on a fresh unlocked instance, never on one already applied to a request
- Treat RequestOptions stored in fields as immutable templates: always clone() before mutating
- Avoid lock() then autoClone() on the same instance
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
- You cannot modify locked T, consider clone()
- Already released
- sizeMultiplier must be between 0 and 1
- Cannot obtain size for recycled Bitmap
- Cannot reset to unset mark position
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)