{"record":{"id":"7d3718c9e74295b0","repo":"apache/druid","slug":"s3-requires-the-s-parameter-if-s-is-set","errorCode":null,"errorMessage":"S3 requires the %s parameter if %s is set","messagePattern":"S3 requires the (.+?) parameter if (.+?) is set","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":207,"sourceCode":"        SECURITY_PARAMS\n    );\n  }\n\n  @Override\n  protected void convertArgsToSourceMap(Map<String, Object> jsonMap, Map<String, Object> args)\n  {\n    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,","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/s3-extensions/src/main/java/org/apache/druid/catalog/model/table/S3InputSourceDefn.java#L189-L225","documentation":"The ad-hoc S3 table function's paths parameter is a shorthand for (prefix = bucket + path), so it is only meaningful when the bucket parameter is also provided. Druid throws this IllegalArgumentException in convertArgsToSourceMap when paths is non-empty but bucket is missing. Without a bucket there is no way to resolve the relative paths.","triggerScenarios":"Calling the S3 EXTERNAL table function with the PATHS parameter set to a non-empty array while the BUCKET parameter is null or blank.","commonSituations":"Specifying relative object paths like data/year=2024/ but forgetting the bucket name; converting an old spec that embedded full URIs into a paths-based call and dropping bucket in the process.","solutions":["Add the bucket parameter alongside paths","Convert the paths into full s3:// URIs and pass them via the uris parameter instead","Remove the paths parameter if bucket-based prefixes are not intended"],"exampleFix":"// before\nEXTERNAL(... paths => ARRAY['data/2024/'], ...) \n// after\nEXTERNAL(... bucket => 'my-bucket', paths => ARRAY['data/2024/'], ...)","handlingStrategy":"validation","validationCode":"if (paths != null && !paths.isEmpty() && (bucket == null || bucket.isBlank())) {\n  throw new IllegalArgumentException(\"bucket is required when paths is provided\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  runExternalQuery(args);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"requires the\")) { /* prompt for bucket and retry */ }\n}","preventionTips":["Always pass bucket when using the paths parameter","Prefer full s3:// uris via the uris parameter to avoid relative-path pitfalls","Validate function arguments in the client before issuing the SQL"],"tags":["s3","sql","missing-parameter","table-function"],"backgroundTag":"missing-required-argument","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"}