apache/hadoop · error · IllegalArgumentException
GCS path must not have consecutive '/' characters: '%s'
Error message
GCS path must not have consecutive '/' characters: '%s'
What it means
Thrown by StringPaths.validateObjectName (hadoop-gcp GoogleHadoopFileSystem) when the object-name part of a gs:// path contains two or more consecutive '/' characters. The connector deliberately makes object names look like traditional filesystem paths, so 'a//b' is rejected with an IllegalArgumentException during path decoding, before any GCS request is made. It is a client-side validation error, not a server response.
Source
Thrown at hadoop-cloud-storage-project/hadoop-gcp/src/main/java/org/apache/hadoop/fs/gs/StringPaths.java:97
*/
static String validateObjectName(String objectName, boolean allowEmptyObjectName) {
LOG.trace("validateObjectName('{}', {})", objectName, allowEmptyObjectName);
if (isNullOrEmpty(objectName) || objectName.equals(PATH_DELIMITER)) {
if (allowEmptyObjectName) {
objectName = "";
} else {
throw new IllegalArgumentException(String.format(
"GCS path must include non-empty object name [objectName='%s',"
+ " allowEmptyObjectName=%s]", objectName, allowEmptyObjectName));
}
}
// We want objectName to look like a traditional file system path,
// therefore, disallow objectName with consecutive '/' chars.
for (int i = 0; i < (objectName.length() - 1); i++) {
if (objectName.charAt(i) == '/' && objectName.charAt(i + 1) == '/') {
throw new IllegalArgumentException(
String.format("GCS path must not have consecutive '/' characters: '%s'", objectName));
}
}
// Remove leading '/' if it exists.
if (objectName.startsWith(PATH_DELIMITER)) {
objectName = objectName.substring(1);
}
LOG.trace("validateObjectName -> '{}'", objectName);
return objectName;
}
/**
* Helper for standardizing the way various human-readable messages in logs/exceptions that refer
* to a bucket/object pair.
*/
public static String fromComponents(String bucketName, String objectName) {View on GitHub (pinned to 2add963021)
Solutions
- Normalize the key before use: replace runs of '/' with a single '/', e.g. key.replaceAll("/+", "/") and trim leading '/'.
- Build paths with Hadoop Path API (new Path(parent, name)) or GoogleCloudStorageFileSystem helper methods instead of string concatenation.
- Validate external/config-supplied paths with a regex like .*(//).* and reject early with a clear message.
- If double slashes are genuinely required in the object name, GCS object names must be built through the raw GoogleCloudStorage API, not the filesystem layer.
Example fix
// before
String key = dir + "/" + "/" + fileName; // dir ends with '/'
gfs.open(new Path("gs://" + bucket + "/" + key));
// after
String key = (dir + "/" + fileName).replaceAll("/+", "/");
gfs.open(new Path("gs://" + bucket + "/" + key)); Defensive patterns
Strategy: validation
Validate before calling
static boolean hasConsecutiveSlashes(String objectName) {
for (int i = 0; i + 1 < objectName.length(); i++) {
if (objectName.charAt(i) == '/' && objectName.charAt(i + 1) == '/') return true;
}
return false;
}
// before any GHFS call:
String key = raw.replaceAll("/+", "/");
if (hasConsecutiveSlashes(key)) throw new IllegalArgumentException("bad key: " + raw); Type guard
// Java idiom: guard returning a sanitized value
static String asGcsObjectName(String raw) {
String k = raw.replaceAll("/+", "/");
if (k.startsWith("/")) k = k.substring(1);
if (k.contains("//")) throw new IllegalArgumentException("Unfixable key: " + raw);
return k;
} Try / catch
try {
fs.open(new Path("gs://bucket/" + key));
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().contains("consecutive '/'")) {
throw new ConfigException("Path normalization bug for key: " + key, e);
}
throw e;
} Prevention
- Always join paths with new Path(parent, child), never string concatenation.
- Run key = key.replaceAll("/+", "/") at system boundaries (user input, config).
- Add a unit test asserting generated keys never match //.
When it happens
Trigger: Calling GHFS APIs with a Path whose decoded object name contains '//': e.g. new Path("gs://bucket/dir//file") passed through UriPaths/StringPaths decoding; building keys by string concatenation (dir + "/" + "/" + name); passing raw strings from config or user input as object names; using Path.toString()+"/"+x instead of Path construction.
Common situations: Spark/Hive jobs assembling partition paths with string concat ("/year=2026/" + "/part-0"); paths derived from URLs that keep empty segments; renaming/copying data whose source keys contain '//' into gs://; custom InputFormat splitters producing empty path segments.
Related errors
- Invalid bucket name (%s) or object name (%s)
- Object %s already exists.
- Error accessing Bucket %s
- Error accessing %s
- Bucket doesn't match for source '%s' and destination '%s'!
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/cae2d34f71e32a85.
Report an issue: GitHub.