{"record":{"id":"7df52b214b9ebfae","repo":"apache/druid","slug":"when-using-the-s-parameter-s-must-also-be-provi","errorCode":null,"errorMessage":"When using the %s parameter, %s must also be provided","messagePattern":"When using the (.+?) parameter, (.+?) must also be provided","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":237,"sourceCode":"      );\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) {\n      jsonMap.put(PREFIXES_FIELD, prefixes);\n    }\n    if (hasBucket) {\n      if (!hasPaths) {\n        throw new IAE(\"When using the %s parameter, %s must also be provided\", BUCKET_PARAMETER, PATHS_PARAMETER);\n      }\n      List<CloudObjectLocation> objects = new ArrayList<>();\n      for (String obj : paths) {\n        objects.add(new CloudObjectLocation(bucket, obj));\n      }\n      jsonMap.put(OBJECTS_FIELD, objects);\n    }\n    if (objectGlob != null) {\n      jsonMap.put(OBJECT_GLOB_FIELD, objectGlob);\n    }\n    applySecurityParams(jsonMap, args);\n  }\n\n  private void applySecurityParams(Map<String, Object> jsonMap, Map<String, Object> args)\n  {\n    final String accessKeyId = CatalogUtils.getNonBlankString(args, ACCESS_KEY_ID_PARAMETER);\n    final String secretAccessKey = CatalogUtils.getNonBlankString(args, SECRET_ACCESS_KEY_PARAMETER);\n    final String assumeRoleArn = CatalogUtils.getNonBlankString(args, ASSUME_ROLE_ARN_PARAMETER);","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/s3-extensions/src/main/java/org/apache/druid/catalog/model/table/S3InputSourceDefn.java#L219-L255","documentation":"The S3 external table definition throws this IllegalArgumentException when the 'bucket' parameter is provided but the 'paths' parameter is absent. A bucket alone does not identify any objects; Druid needs the object keys (paths) within the bucket to build CloudObjectLocation entries. Bucket + paths are treated as a paired unit for the objects-based S3 input source.","triggerScenarios":"Calling the S3 external table function with a 'bucket' argument but no 'paths' argument, so hasBucket is true and hasPaths is false inside convertArgsToSourceMap.","commonSituations":"Assuming 'bucket' alone selects the whole bucket (that is what 'prefixes' is for); copying a config snippet that included bucket but dropping the paths line; building the argument map programmatically and leaving out the paths key.","solutions":["Add the 'paths' parameter listing the object keys in the bucket.","If the intent was to read everything under a prefix, drop 'bucket' and use the 'prefixes' parameter instead.","If the intent was explicit files, pass full s3:// URIs via 'paths'/'uris' instead of bucket + keys.","Review the table function argument map for the missing 'paths' key before invoking."],"exampleFix":"// before\nEXTERN('s3-ext' => ARRAY[], 'bucket' => 'my-bucket')\n// after\nEXTERN('s3-ext' => ARRAY['data/file1.json','data/file2.json'], 'bucket' => 'my-bucket')","handlingStrategy":"validation","validationCode":"Object bucket = args.get(\"bucket\");\nList<?> paths = (List<?>) args.getOrDefault(\"paths\", List.of());\nif (bucket != null && paths.isEmpty()) {\n  throw new IllegalArgumentException(\"'bucket' requires a non-empty 'paths' list of object keys\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat bucket and paths as a mandatory pair in your SQL/config templates","Use prefixes instead of bucket when you want prefix-based discovery","Check for empty arrays, not just null, when validating paths"],"tags":["validation","input-source","s3","missing-argument","paired-parameters"],"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"}