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

  1. Normalize the key before use: replace runs of '/' with a single '/', e.g. key.replaceAll("/+", "/") and trim leading '/'.
  2. Build paths with Hadoop Path API (new Path(parent, name)) or GoogleCloudStorageFileSystem helper methods instead of string concatenation.
  3. Validate external/config-supplied paths with a regex like .*(//).* and reject early with a clear message.
  4. 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

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


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/cae2d34f71e32a85. Report an issue: GitHub.