{"record":{"id":"b73f180ff6600885","repo":"bumptech/glide","slug":"you-can-t-start-or-clear-loads-in-requestlistener","errorCode":null,"errorMessage":"You can't start or clear loads in RequestListener or Target callbacks. If you're trying to start a fallback request when a load fails, use RequestBuilder#error(RequestBuilder). Otherwise consider posting your into() or clear() calls to the main thread using a Handler instead.","messagePattern":"You can't start or clear loads in RequestListener or Target callbacks\\. If you're trying to start a fallback request when a load fails, use RequestBuilder#error\\(RequestBuilder\\)\\. Otherwise consider posting your into\\(\\) or clear\\(\\) calls to the main thread using a Handler instead\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"library/src/main/java/com/bumptech/glide/request/SingleRequest.java","lineNumber":307,"sourceCode":"   *\n   * @see #clear()\n   */\n  @GuardedBy(\"requestLock\")\n  private void cancel() {\n    assertNotCallingCallbacks();\n    stateVerifier.throwIfRecycled();\n    target.removeCallback(this);\n    if (loadStatus != null) {\n      loadStatus.cancel();\n      loadStatus = null;\n    }\n  }\n\n  // Avoids difficult to understand errors like #2413.\n  @GuardedBy(\"requestLock\")\n  private void assertNotCallingCallbacks() {\n    if (isCallingCallbacks) {\n      throw new IllegalStateException(\n          \"You can't start or clear loads in RequestListener or\"\n              + \" Target callbacks. If you're trying to start a fallback request when a load fails,\"\n              + \" use RequestBuilder#error(RequestBuilder). Otherwise consider posting your into()\"\n              + \" or clear() calls to the main thread using a Handler instead.\");\n    }\n  }\n\n  /**\n   * Cancels the current load if it is in progress, clears any resources held onto by the request\n   * and replaces the loaded resource if the load completed with the placeholder.\n   *\n   * <p>Cleared requests can be restarted with a subsequent call to {@link #begin()}\n   *\n   * @see #cancel()\n   */\n  @Override\n  public void clear() {\n    Resource<R> toRelease = null;","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/bumptech/glide/blob/eb14a895d8f866e6a08c3e19d50ea3bd2c12c20a/library/src/main/java/com/bumptech/glide/request/SingleRequest.java#L289-L325","documentation":"Thrown by SingleRequest.assertNotCallingCallbacks() (invoked at the start of begin/clear) when isCallingCallbacks is true — i.e. you are synchronously inside a RequestListener.onResourceReady/onLoadFailed or a Target callback (onResourceReady, onLoadFailed, onLoadCleared) and you attempt to start a new Glide load or clear one from within that callback. Glide holds the requestLock during callbacks and re-entrant start/clear would deadlock or corrupt state, hence the explicit guard (issue #2413).","triggerScenarios":"Inside RequestListener.onResourceReady starting Glide.with(...).load(fallbackUrl).into(target); inside Target.onLoadFailed calling clear() on the same request; chaining a thumbnail->error request manually inside the listener rather than using RequestBuilder.error(RequestBuilder).","commonSituations":"Implementing a fallback-image pattern manually in onLoadFailed; preloading the next image inside onResourceReady; calling notifyDataSetChanged() that synchronously triggers a Glide.into() from within a callback.","solutions":["For fallback-on-failure use the built-in API: .load(primary).error(Glide.with(ctx).load(fallback))","If you must start a new load from a callback, post it to the main thread Handler (or use view.post { }) so it runs after the callback returns","Use RequestBuilder.thumbnail() or .error(RequestBuilder) for chained loads instead of doing them in listeners","Never call RequestManager.clear(target) for the same target from inside that target's own callback"],"exampleFix":"// before\nlistener = object : RequestListener<Drawable> {\n  override fun onLoadFailed(...): Boolean {\n    Glide.with(view).load(fallbackUrl).into(target) // IllegalStateException\n    return true\n  }\n}\n\n// after - use the error(RequestBuilder) API\nGlide.with(view)\n  .load(primaryUrl)\n  .error(Glide.with(view).load(fallbackUrl))\n  .into(target)","handlingStrategy":"fallback","validationCode":"// Structural rule: do NOT start/clear loads inside RequestListener/Target callbacks.\n// Use RequestBuilder.error(RequestBuilder) for fallback loads instead.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use .error(Glide.with(ctx).load(fallback)) for fallback-on-failure instead of listener-driven loads","If a callback must trigger a load, post it: view.post { Glide.with(view)... }","Never call RequestManager.clear(target) for the same target inside that target's own callback"],"tags":["android","glide","callbacks","concurrency","reentrancy","lifecycle"],"backgroundTag":null,"analyzedSha":"eb14a895d8f866e6a08c3e19d50ea3bd2c12c20a","analyzedAt":"2026-08-14T01:43:54.821Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}