{"record":{"id":"f13d1413c782ce65","repo":"apache/druid","slug":"s3-accepts-only-one-of-s-s-or-s","errorCode":null,"errorMessage":"S3 accepts only one of %s, %s or %s","messagePattern":"S3 accepts only one of (.+?), (.+?) or (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions-core/s3-extensions/src/main/java/org/apache/druid/catalog/model/table/S3InputSourceDefn.java","lineNumber":214,"sourceCode":"    jsonMap.put(InputSource.TYPE_PROPERTY, S3StorageDruidModule.SCHEME);\n    final List<String> uris = CatalogUtils.getStringArray(args, URIS_PARAMETER);\n    final List<String> prefixes = CatalogUtils.getStringArray(args, PREFIXES_PARAMETER);\n    final String bucket = CatalogUtils.getNonBlankString(args, BUCKET_PARAMETER);\n    final List<String> paths = CatalogUtils.getStringArray(args, PATHS_PARAMETER);\n    final String objectGlob = CatalogUtils.getNonBlankString(args, OBJECT_GLOB_PARAMETER);\n    final boolean hasUris = uris != null;\n    final boolean hasPrefixes = prefixes != null;\n    final boolean hasBucket = bucket != null;\n    final boolean hasPaths = !CollectionUtils.isNullOrEmpty(paths);\n    if (hasPaths && !hasBucket) {\n      throw new IAE(\n          \"S3 requires the %s parameter if %s is set\",\n          BUCKET_PARAMETER,\n          PATHS_PARAMETER\n      );\n    }\n    if ((hasUris && (hasPrefixes || hasBucket)) || (hasPrefixes && hasBucket)) {\n      throw new IAE(\n          \"S3 accepts only one of %s, %s or %s\",\n          PATHS_PARAMETER,\n          BUCKET_PARAMETER,\n          PREFIXES_PARAMETER\n      );\n    }\n    if (!hasUris && !hasPrefixes && !hasBucket) {\n      throw new IAE(\n          \"S3 requires one of %s, %s or %s\",\n          PATHS_PARAMETER,\n          BUCKET_PARAMETER,\n          PREFIXES_PARAMETER\n      );\n    }\n    if (hasUris) {\n      jsonMap.put(URIS_FIELD, CatalogUtils.stringListToUriList(uris));\n    }\n    if (hasPrefixes) {","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/s3-extensions/src/main/java/org/apache/druid/catalog/model/table/S3InputSourceDefn.java#L196-L232","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Keep only one of uris, prefixes, or bucket (plus paths if bucket is used)","If both a bucket and specific objects are desired, express them as full s3:// uris in the uris parameter","Use prefixes alone, encoding the bucket inside each prefix URI"],"exampleFix":"// before\nEXTERNAL(... uris => ARRAY['s3://b/a.json'], bucket => 'b', ...)\n// after\nEXTERNAL(... uris => ARRAY['s3://b/a.json'], ...)","handlingStrategy":"validation","validationCode":"int selectors = (uris != null ? 1 : 0) + (prefixes != null ? 1 : 0) + (bucket != null ? 1 : 0);\nif (selectors > 1) {\n  throw new IllegalArgumentException(\"Provide only one of uris, prefixes, or bucket\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  runExternalQuery(args);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"accepts only one of\")) { /* keep one selector and retry */ }\n}","preventionTips":["Build the SQL from one canonical location parameter in application code","Never append all S3 location parameters from a config map; select one explicitly","Convert bucket+object combinations into full s3:// uris before calling the function"],"tags":["s3","sql","conflicting-parameters","table-function"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}