apache/druid · error · IllegalArgumentException

S3 accepts only one of %s, %s or %s

Error message

S3 accepts only one of %s, %s or %s

What it means

The S3 table function accepts exactly one primary location selector among paths (with bucket), bucket, and prefixes; uris may only appear alone. Druid throws this IllegalArgumentException when more than one of uris, prefixes, or bucket is supplied, since combining them is ambiguous. Each parameter describes a different way of enumerating S3 objects and they cannot be merged.

Source

Thrown at extensions-core/s3-extensions/src/main/java/org/apache/druid/catalog/model/table/S3InputSourceDefn.java:214

    jsonMap.put(InputSource.TYPE_PROPERTY, S3StorageDruidModule.SCHEME);
    final List<String> uris = CatalogUtils.getStringArray(args, URIS_PARAMETER);
    final List<String> prefixes = CatalogUtils.getStringArray(args, PREFIXES_PARAMETER);
    final String bucket = CatalogUtils.getNonBlankString(args, BUCKET_PARAMETER);
    final List<String> paths = CatalogUtils.getStringArray(args, PATHS_PARAMETER);
    final String objectGlob = CatalogUtils.getNonBlankString(args, OBJECT_GLOB_PARAMETER);
    final boolean hasUris = uris != null;
    final boolean hasPrefixes = prefixes != null;
    final boolean hasBucket = bucket != null;
    final boolean hasPaths = !CollectionUtils.isNullOrEmpty(paths);
    if (hasPaths && !hasBucket) {
      throw new IAE(
          "S3 requires the %s parameter if %s is set",
          BUCKET_PARAMETER,
          PATHS_PARAMETER
      );
    }
    if ((hasUris && (hasPrefixes || hasBucket)) || (hasPrefixes && hasBucket)) {
      throw new IAE(
          "S3 accepts only one of %s, %s or %s",
          PATHS_PARAMETER,
          BUCKET_PARAMETER,
          PREFIXES_PARAMETER
      );
    }
    if (!hasUris && !hasPrefixes && !hasBucket) {
      throw new IAE(
          "S3 requires one of %s, %s or %s",
          PATHS_PARAMETER,
          BUCKET_PARAMETER,
          PREFIXES_PARAMETER
      );
    }
    if (hasUris) {
      jsonMap.put(URIS_FIELD, CatalogUtils.stringListToUriList(uris));
    }
    if (hasPrefixes) {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Keep only one of uris, prefixes, or bucket (plus paths if bucket is used)
  2. If both a bucket and specific objects are desired, express them as full s3:// uris in the uris parameter
  3. Use prefixes alone, encoding the bucket inside each prefix URI

Example fix

// before
EXTERNAL(... uris => ARRAY['s3://b/a.json'], bucket => 'b', ...)
// after
EXTERNAL(... uris => ARRAY['s3://b/a.json'], ...)
Defensive patterns

Strategy: validation

Validate before calling

int selectors = (uris != null ? 1 : 0) + (prefixes != null ? 1 : 0) + (bucket != null ? 1 : 0);
if (selectors > 1) {
  throw new IllegalArgumentException("Provide only one of uris, prefixes, or bucket");
}

Try / catch

try {
  runExternalQuery(args);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("accepts only one of")) { /* keep one selector and retry */ }
}

Prevention

When it happens

Trigger: Calling the S3 EXTERNAL table function with any two of uris, prefixes, or bucket set simultaneously (e.g. uris plus bucket, or prefixes plus bucket).

Common situations: Adding a bucket parameter to a working uris-based call thinking it narrows the search; script-generated SQL that appends all location parameters; combining prefixes with bucket to try to 'scope' prefixes.

Understand the failure class

Background: "mutually exclusive" flag errors: what "can't supply both nx and xx", "--raw is not compatible with -i" and "cannot be used with" mean, and how to fix them — this error's family across 29 libraries.

Related errors


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