didi/DoKit · error · IllegalStateException

Downloader already set.

Error message

Downloader already set.

What it means

DokitPicasso.Builder.downloader() throws IllegalStateException when a Downloader has already been assigned to this builder. The builder enforces one-shot configuration for each component to avoid silently replacing a configured downloader. This mirrors upstream Picasso's builder contract.

Source

Thrown at Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/DokitPicasso.java:725

    /**
     * Specify the default {@link Bitmap.Config} used when decoding images. This can be overridden
     * on a per-request basis using {@link RequestCreator#config(Bitmap.Config) config(..)}.
     */
    public Builder defaultBitmapConfig(Bitmap.Config bitmapConfig) {
      if (bitmapConfig == null) {
        throw new IllegalArgumentException("Bitmap config must not be null.");
      }
      this.defaultBitmapConfig = bitmapConfig;
      return this;
    }

    /** Specify the {@link Downloader} that will be used for downloading images. */
    public Builder downloader(Downloader downloader) {
      if (downloader == null) {
        throw new IllegalArgumentException("Downloader must not be null.");
      }
      if (this.downloader != null) {
        throw new IllegalStateException("Downloader already set.");
      }
      this.downloader = downloader;
      return this;
    }

    /**
     * Specify the executor service for loading images in the background.
     * <p>
     * Note: Calling {@link DokitPicasso#shutdown() shutdown()} will not shutdown supplied executors.
     */
    public Builder executor(ExecutorService executorService) {
      if (executorService == null) {
        throw new IllegalArgumentException("Executor service must not be null.");
      }
      if (this.service != null) {
        throw new IllegalStateException("Executor service already set.");
      }
      this.service = executorService;

View on GitHub (pinned to 626827cddb)

Solutions

  1. Remove the duplicate downloader() call so it is invoked exactly once per Builder
  2. If you need to replace a downloader, create a fresh Builder and configure it once
  3. Track whether the builder was already configured before calling downloader() again

Example fix

// before
builder.downloader(defaultDownloader);
builder.downloader(new OkHttp3Downloader(client)); // IllegalStateException

// after
builder.downloader(new OkHttp3Downloader(client));
Defensive patterns

Strategy: validation

Validate before calling

// Set the downloader exactly once; track it yourself
if (builderHasDownloader) { throw new IllegalStateException("configure downloader once"); }
builder.downloader(new OkHttp3Downloader(client));
builderHasDownloader = true;

Try / catch

try { builder.downloader(d); } catch (IllegalStateException e) { if (!e.getMessage().contains("Downloader already set")) throw e; log("downloader already configured"); }

Prevention

When it happens

Trigger: Calling builder.downloader(d) a second time on the same Builder instance, e.g. applying a default downloader and then overriding it with a custom OkHttp downloader.

Common situations: Copy-pasted configuration code that sets a downloader in two places; a shared builder passed through several config methods; upgrading code that injected a new downloader without removing the old call.

Related errors


AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14). Data as JSON: /api/errors/3cd8607450ac424f. Report an issue: GitHub.