apache/beam · error · IllegalArgumentException
projectId can't be empty
Error message
projectId can't be empty
What it means
SpannerTransformRegistrar's Configuration (the cross-language/schematized transform registration for SpannerRead) validates mandatory fields via checkMandatoryFields(); an empty projectId throws IllegalArgumentException("projectId can't be empty"). A Spanner connection is impossible without a project, so this fails fast at configuration time.
Source
Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerTransformRegistrar.java:125
public void setExperimentalHost(@Nullable String experimentalHost) {
this.experimentalHost = experimentalHost;
}
public void setPlainText(@Nullable Boolean plainText) {
this.plainText = plainText;
}
public void setClientCertPath(@Nullable String clientCertPath) {
this.clientCertPath = clientCertPath;
}
public void setClientCertKeyPath(@Nullable String clientCertKeyPath) {
this.clientCertKeyPath = clientCertKeyPath;
}
void checkMandatoryFields() {
if (projectId.isEmpty()) {
throw new IllegalArgumentException("projectId can't be empty");
}
if (databaseId.isEmpty()) {
throw new IllegalArgumentException("databaseId can't be empty");
}
if (instanceId.isEmpty()) {
throw new IllegalArgumentException("instanceId can't be empty");
}
if ((clientCertPath != null) != (clientCertKeyPath != null)) {
throw new IllegalArgumentException(
"Both clientCertPath and clientCertKeyPath must be specified together.");
}
}
}
public static class ReadBuilder
implements ExternalTransformBuilder<ReadBuilder.Configuration, PBegin, PCollection<Row>> {
public static class Configuration extends CrossLanguageConfiguration {View on GitHub (pinned to 12126d8942)
Solutions
- Set projectId explicitly: SpannerConfig.create().withProjectId("my-project") or pass the projectId parameter to the transform.
- When using pipeline options, wire the GcpOptions.getProject() into the Spanner config instead of relying on defaults.
- For cross-language/YAML usage, supply the projectId field in the transform's arguments.
- Validate the config object (projectId, instanceId, databaseId all non-empty) before submitting the pipeline.
Example fix
// before
SpannerConfig config = SpannerConfig.create().withInstanceId("my-instance").withDatabaseId("my-db");
// after
SpannerConfig config = SpannerConfig.create()
.withProjectId("my-gcp-project")
.withInstanceId("my-instance")
.withDatabaseId("my-db"); Defensive patterns
Strategy: validation
Validate before calling
Preconditions.checkArgument(
config.getProjectId() != null && !config.getProjectId().isEmpty(), "projectId must be set");
Preconditions.checkArgument(!config.getInstanceId().isEmpty(), "instanceId must be set");
Preconditions.checkArgument(!config.getDatabaseId().isEmpty(), "databaseId must be set"); Try / catch
try { pipeline.apply(SpannerRead.of(config).withTable(t)); } catch (IllegalArgumentException e) { if (e.getMessage().contains("projectId can't be empty")) { config = config.withProjectId(gcpOptions.getProject()); } else throw e; } Prevention
- Always set withProjectId explicitly rather than relying on ambient defaults.
- Wire GcpOptions project into SpannerConfig in pipeline option processing.
- Validate all three of projectId/instanceId/databaseId before submitting.
When it happens
Trigger: Submitting a Spanner read/write transform (e.g., via cross-language expansion or SpannerTransformRegistrar.Configuration) where the projectId option was not set or was set to an empty string before checkMandatoryFields() runs.
Common situations: Omitting --projectId in pipeline options when constructing the transform from YAML/SQL/cross-language pipelines; env-provided GCP project not propagated into the configuration; typo between option name and expected key.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Pipeline update will not be possible because the following t
- One or more ErrorHandlers aren't closed, and this pipeline c
- Failed to validate %s
- Failed to validate %s
- Failed to validate transform %s
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/41c18fbd8fa25c8c.
Report an issue: GitHub.