apache/druid · error · IllegalStateException (ISE)

S3Client supplier cannot be null!

Error message

S3Client supplier cannot be null!

What it means

The ServerSideEncryptingAmazonS3.Builder.build() requires an S3Client supplier to have been set (via s3Client(...) / setS3ClientSupplier). Throwing ISE guards against constructing the encrypting client wrapper with no underlying client factory.

Solutions

  1. Call builder.s3ClientSupplier(() -> S3Client.builder().build()) before build().
  2. Use AWSClientUtil-provided client configuration helpers to build the supplier.
  3. Also ensure s3StorageConfig(...) is set, the next required field.
  4. Update custom wiring to match the current S3StorageDruidModule setup.

Example fix

// before
ServerSideEncryptingAmazonS3 s3 = new ServerSideEncryptingAmazonS3.Builder().build();
// after
ServerSideEncryptingAmazonS3 s3 = new ServerSideEncryptingAmazonS3.Builder()
    .s3ClientSupplier(() -> S3Client.create())
    .s3StorageConfig(new S3StorageConfig(ImmutableList.of()))
    .build();
Defensive patterns

Strategy: validation

Validate before calling

if (builder == null) throw new IllegalArgumentException("builder required");
// ensure supplier set before build:
// builder.s3ClientSupplier(...) must have been called

Try / catch

try { s3 = builder.build(); } catch (IllegalStateException e) { throw new IllegalStateException("wire s3ClientSupplier/s3StorageConfig before build()", e); }

Prevention

When it happens

Trigger: Calling builder.build() without first invoking s3ClientSupplier(...), typically in custom extension code or tests wiring ServerSideEncryptingAmazonS3 manually.

Common situations: Hand-rolled module/Google Guice bindings copying an outdated example; tests constructing the builder but forgetting the supplier step; refactors that renamed the setter.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/c418a3dfc620c1a7. Report an issue: GitHub.

Appendix: source

Thrown at extensions-core/s3-extensions/src/main/java/org/apache/druid/storage/s3/ServerSideEncryptingAmazonS3.java:543

    }

    /**
     * Builds a new {@link ServerSideEncryptingAmazonS3} instance.
     *
     * <p><b>Resource leak warning:</b> Each instance created by this method holds internal resources such as thread
     * pools and connection pools. {@link ServerSideEncryptingAmazonS3} is not {@link java.io.Closeable}, so there is
     * currently no way for callers to release these resources when the instance is no longer needed. Avoid calling
     * this method repeatedly (e.g., once per file or per task) when a single shared instance would suffice. Consider
     * memoizing the result, as {@link org.apache.druid.data.input.s3.S3InputSource} does, to ensure the client is
     * created at most once per configuration.
     *
     * <p>The long-term fix is to make {@link ServerSideEncryptingAmazonS3} implement {@link java.io.Closeable} and
     * arrange for {@code close()} to be called appropriately, but that is a larger change deferred for the future.
     */
    public ServerSideEncryptingAmazonS3 build()
    {
      if (s3ClientSupplier == null) {
        throw new ISE("S3Client supplier cannot be null!");
      }
      if (s3StorageConfig == null) {
        throw new ISE("S3StorageConfig cannot be null!");
      }

      S3Client s3Client;
      try {
        s3Client = S3Utils.retryS3Operation(s3ClientSupplier::get);
      }
      catch (Exception e) {
        throw new RuntimeException(e);
      }

      S3AsyncClient s3AsyncClient = null;
      if (s3AsyncClientSupplier != null) {
        try {
          s3AsyncClient = S3Utils.retryS3Operation(s3AsyncClientSupplier::get);
        }

View on GitHub (pinned to 9b90983fd2)