apache/beam · error · java.lang.IllegalArgumentException
stagingBucketName must end with '/'
Error message
stagingBucketName must end with '/'
What it means
SnowflakeWriteConfiguration.validate() requires the staging bucket name to end with a trailing slash. The Snowflake IO composes storage integration paths by directly appending to the staging bucket name, so a missing trailing slash would produce malformed GCS/S3 paths during COPY operations. The check runs eagerly at pipeline construction time via IllegalArgumentException.
Solutions
- Append a '/' to the staging bucket name, e.g. change 'gs://my-bucket' to 'gs://my-bucket/'.
- If the value comes from a config file or pipeline option, sanitize it before building the configuration (value.endsWith("/") ? value : value + "/").
- Check the storage integration in Snowflake points at the same bucket root if paths still misbehave after the fix.
Example fix
// before
.withStagingBucketName("gs://my-snowflake-bucket")
// after
.withStagingBucketName("gs://my-snowflake-bucket/") Defensive patterns
Strategy: validation
Validate before calling
String bucket = cfg.getStagingBucketName();
if (bucket != null && !bucket.endsWith("/")) {
bucket = bucket + "/";
} Try / catch
try {
config.validate();
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("stagingBucketName")) { /* fix trailing slash and retry */ }
throw e;
} Prevention
- Normalize bucket strings with a small helper that guarantees a trailing slash before building the configuration.
- Store bucket paths in config with the trailing slash already included and document this convention.
- Run configuration.validate() in unit tests with production config fixtures.
When it happens
Trigger: Calling SnowflakeWriteConfiguration (or the Snowflake write SchemaTransform) with stagingBucketName set to e.g. 'gs://my-bucket' or 'gs://my-bucket/prefix' instead of 'gs://my-bucket/' or 'gs://my-bucket/prefix/'.
Common situations: Users copy a bucket URL from the cloud console (which omits the trailing slash) or construct the path programmatically with string concatenation and forget the separator; very common in Terraform-generated or template-generated configs.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Either table or query must be specified.
- Failed to setLoginTimeout
- flushRowLimit must be greater than 0.
- flushTimeLimitMillis must be greater than 0.
- name + " cannot be empty"
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/43189ddfc5b134b6.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/io/snowflake/src/main/java/org/apache/beam/sdk/io/snowflake/SnowflakeWriteConfiguration.java:139
public static Builder builder() {
return new AutoValue_SnowflakeWriteConfiguration.Builder();
}
public abstract Builder toBuilder();
void validate() {
requireNonEmpty(getServerName(), "serverName");
requireNonEmpty(getDatabase(), "database");
requireNonEmpty(getSchema(), "schema");
requireNonEmpty(getStagingBucketName(), "stagingBucketName");
requireNonEmpty(getStorageIntegrationName(), "storageIntegrationName");
SnowflakeSchemaTransformUtils.validateAuthentication(
getUsername(), getPassword(), getOauthToken(), getPrivateKey(), getPrivateKeyPassphrase());
if (!getStagingBucketName().endsWith("/")) {
throw new IllegalArgumentException("stagingBucketName must end with '/'");
}
// Parse configured enum values to validate that they are supported.
String createDisposition = getCreateDisposition();
if (createDisposition != null) {
parseCreateDisposition(createDisposition);
}
String writeDisposition = getWriteDisposition();
if (writeDisposition != null) {
parseWriteDisposition(writeDisposition);
}
String debugMode = getDebugMode();
if (debugMode != null) {
parseStreamingLogLevel(debugMode);
}
View on GitHub (pinned to 12126d8942)