apache/druid · error · IllegalArgumentException
Invalid URI scheme [ ] must be [ ]
Error message
Invalid URI scheme [%s] must be [%s]
What it means
CloudObjectLocation.validateUriScheme checks that a URI's scheme case-insensitively matches an expected scheme (e.g. "s3" or "gs") and throws an IAE showing the full URI and the required scheme. It enforces that object locations in a cloud input source use the scheme of the configured storage type.
Solutions
- Change the URI scheme to the expected one (e.g. use s3://bucket/path for S3, gs://bucket/path for GCS).
- Convert s3a:// or s3n:// URIs to s3:// for Druid S3 input sources.
- Ensure the storage type of the inputSource matches the URI scheme of every listed object/prefix.
Example fix
// before
{"type":"google","uris":["s3://bucket/path/file.json"]}
// after
{"type":"google","uris":["gs://bucket/path/file.json"]} Defensive patterns
Strategy: validation
Validate before calling
URI uri = URI.create(location);
String expected = "s3"; // storage type's scheme
if (uri.getScheme() == null || !uri.getScheme().equalsIgnoreCase(expected)) {
throw new IllegalArgumentException("Invalid URI scheme [" + uri + "] must be [" + expected + "]");
} Type guard
String requireScheme(URI uri, String expected) {
return uri.getScheme() != null && uri.getScheme().equalsIgnoreCase(expected)
? uri.toString()
: CloudObjectLocation.validateUriScheme(expected, uri).toString();
} Try / catch
try {
locations.add(new CloudObjectLocation(URI.create(objectUri)));
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Invalid URI scheme")) {
throw new SpecValidationError("Object URI scheme does not match the input source storage type: " + objectUri, e);
}
throw e;
} Prevention
- Match URI schemes to the inputSource type: s3 for S3, gs for GCS, azure for Azure.
- Rewrite s3a:// and s3n:// URIs to s3:// when moving configs from Hadoop to Druid.
- Include the scheme explicitly in every object/prefix URI; never rely on defaults.
- Lint spec files for scheme/storage-type mismatches in CI before deployment.
When it happens
Trigger: Building a CloudObjectLocation or validating a URI whose scheme differs from the expected one, e.g. an "s3://" URI supplied where "gs" is required, an "http://" URI in an s3 inputSource, or "S3A://"-style URIs in S3 specs.
Common situations: Copy-pasting URIs between Google Cloud Storage and S3 ingestion specs; using EMR/hadoop-style s3a or s3n schemes in a Druid s3 inputSource; typos like "ss3://bucket"; forgetting the scheme entirely.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- Exactly one of uris, prefixes or objects must be specified
- Caching is not supported. Check `isCacheable` before…
- Cannot compare against something that is not a…
- Cannot compare against something that is not a…
- Column[ ] is not a valid column
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/9acc66f28909f5ac.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/data/input/impl/CloudObjectLocation.java:52
*
* The intention is that this is used as a common representation for storage objects as an alternative to dealing in
* {@link URI} directly, but still provide a mechanism to round-trip with a URI.
*
* In common clouds, bucket names must be dns compliant:
* https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html
* https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata
* https://cloud.google.com/storage/docs/naming
*
* The constructor ensures that bucket names are DNS compliant by checking that the URL encoded form of the bucket
* matches the supplied value. Technically it should probably confirm that the bucket is also all lower-case, but
* S3 has a legacy mode where buckets did not have to be compliant so we can't enforce that here unfortunately.
*/
public class CloudObjectLocation
{
public static URI validateUriScheme(String scheme, URI uri)
{
if (!scheme.equalsIgnoreCase(uri.getScheme())) {
throw new IAE("Invalid URI scheme [%s] must be [%s]", uri.toString(), scheme);
}
return uri;
}
private final String bucket;
private final String path;
@JsonCreator
public CloudObjectLocation(@JsonProperty("bucket") String bucket, @JsonProperty("path") String path)
{
this.bucket = Preconditions.checkNotNull(StringUtils.maybeRemoveTrailingSlash(bucket),
"bucket name cannot be null. Please verify if bucket name adheres to naming rules");
this.path = Preconditions.checkNotNull(StringUtils.maybeRemoveLeadingSlash(path));
Preconditions.checkArgument(
this.bucket.equals(StringUtils.urlEncode(this.bucket)),
"bucket must follow DNS-compliant naming conventions"
);
}View on GitHub (pinned to 9b90983fd2)