{"record":{"id":"aaf2cb5ef2bb756d","repo":"apache/druid","slug":"provide-either-the-s-property-or-one-of-the-s3-i","errorCode":null,"errorMessage":"Provide either the %s property, or one of the S3 input source fields %s, %s or %s, but not both.","messagePattern":"Provide either the (.+?) property, or one of the S3 input source fields (.+?), (.+?) or (.+?), but not both\\.","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":155,"sourceCode":"    final boolean hasColumns = !CollectionUtils.isNullOrEmpty(table.resolvedTable().spec().columns());\n\n    if (hasFormat && !hasColumns) {\n      throw new IAE(\n          \"An external S3 table with a format must also provide the corresponding columns\"\n      );\n    }\n\n    // The user can either provide a bucket, or can provide one of the valid items.\n    final String bucket = table.resolvedTable().stringProperty(BUCKET_PROPERTY);\n    final boolean hasBucket = bucket != null;\n    final Map<String, Object> sourceMap = table.inputSourceMap;\n    final boolean hasUris = sourceMap.containsKey(URIS_FIELD);\n    final boolean hasPrefix = sourceMap.containsKey(PREFIXES_FIELD);\n    final boolean hasObjects = sourceMap.containsKey(OBJECTS_FIELD);\n    final boolean hasGlob = sourceMap.containsKey(OBJECT_GLOB_FIELD);\n    if (hasBucket) {\n      if (hasUris || hasPrefix || hasObjects) {\n        throw new IAE(\n            \"Provide either the %s property, or one of the S3 input source fields %s, %s or %s, but not both.\",\n            BUCKET_PROPERTY,\n            URIS_FIELD,\n            PREFIXES_FIELD,\n            OBJECTS_FIELD\n        );\n      }\n      if (hasGlob) {\n        throw new IAE(\n            \"The %s property cannot be provided when the %s property is set\",\n            OBJECT_GLOB_FIELD,\n            BUCKET_PROPERTY\n        );\n      }\n\n      // Patch in a dummy URI so that validation of the rest of the fields\n      // will pass.\n      sourceMap.put(URIS_FIELD, Collections.singletonList(bucket));","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/s3-extensions/src/main/java/org/apache/druid/catalog/model/table/S3InputSourceDefn.java#L137-L173","documentation":"The catalog S3 table supports two mutually exclusive addressing styles: a bucket property on the table, or S3 input-source fields (uris/prefixes/objects) inside the inputSourceMap. Druid throws this IllegalArgumentException when both styles are supplied, since it cannot decide which targeting to use. The bucket style gets translated into a synthetic uris entry internally.","triggerScenarios":"Calling validate() on a ResolvedExternalTable where the bucket property is set on the table spec AND the inputSourceMap contains any of the keys uris, prefixes, or objects.","commonSituations":"Combining an example table spec that uses bucket with an inputSource copied from a raw S3InputSource JSON that uses uris or prefixes; template-generated specs where both mechanisms were filled in.","solutions":["Remove the bucket property and keep only the uris/prefixes/objects fields in the inputSource","Or remove the uris/prefixes/objects fields and specify only the bucket property","Check whether a template or migration tool duplicated location settings and keep one"],"exampleFix":"// before\n{\"bucket\": \"my-bucket\", \"inputSource\": {\"type\": \"s3\", \"uris\": [\"s3://my-bucket/data/\"]}}\n// after\n{\"inputSource\": {\"type\": \"s3\", \"uris\": [\"s3://my-bucket/data/\"]}}","handlingStrategy":"validation","validationCode":"boolean hasBucket = spec.stringProperty(\"bucket\") != null;\nMap<String, Object> src = spec.inputSourceMap;\nif (hasBucket && (src.containsKey(\"uris\") || src.containsKey(\"prefixes\") || src.containsKey(\"objects\"))) {\n  throw new IllegalArgumentException(\"bucket and uris/prefixes/objects are mutually exclusive\");\n}","typeGuard":"boolean usesOnlyOneAddressing(String bucket, Map<String, Object> src) {\n  boolean hasListFields = src.containsKey(\"uris\") || src.containsKey(\"prefixes\") || src.containsKey(\"objects\");\n  return !(bucket != null && hasListFields);\n}","tryCatchPattern":"try {\n  tableDefn.validate(table);\n} catch (IllegalArgumentException e) {\n  // strip uris/prefixes/objects when bucket is set, then retry\n}","preventionTips":["Pick one addressing style per table: bucket OR uris/prefixes/objects","Never merge raw S3InputSource JSON fragments into catalog table specs without review","Write a pre-submit validator mirroring the catalog's rules"],"tags":["s3","catalog","conflicting-parameters","validation"],"backgroundTag":"mutually-exclusive-options","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"}