apache/beam · error · IllegalArgumentException
instanceId can't be empty
Error message
instanceId can't be empty
What it means
checkMandatoryFields() in SpannerTransformRegistrar enforces that an instanceId is provided alongside projectId and databaseId. A Cloud Spanner resource path is projects/<p>/instances/<i>/databases/<d>; without instanceId the client cannot build it, so the library throws IllegalArgumentException early. It indicates the Spanner builder was constructed incompletely.
Source
Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerTransformRegistrar.java:131
}
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 {
// TODO: https://github.com/apache/beam/issues/20415 Come up with something to determine
// schema without this explicit parameter
private Schema schema = Schema.builder().build();
private @Nullable String sql;
private @Nullable String table;
private @Nullable Boolean batching;View on GitHub (pinned to 12126d8942)
Solutions
- Add .withInstanceId("<your-instance>") to the Spanner builder.
- If derived from options, default it correctly or fail with a clear message before building the transform.
- Confirm the instance name with `gcloud spanner instances list`.
Example fix
// before
SpannerIO.read().withProjectId("p").withDatabaseId("db")
// after
SpannerIO.read().withProjectId("p").withInstanceId("i").withDatabaseId("db") Defensive patterns
Strategy: validation
Validate before calling
if (instanceId == null || instanceId.isEmpty()) { throw new IllegalArgumentException("instanceId must be set before building the Spanner transform"); } Try / catch
try { return SpannerIO.read().withInstanceId(instanceId).withDatabaseId(db).withProjectId(p); } catch (IllegalArgumentException e) { throw new PipelineConfigException("Missing Spanner instanceId", e); } Prevention
- Centralize Spanner config resolution in one factory that asserts all three identifiers.
- Document required CLI/pipeline options and add a --dry-run config check.
- Verify instance names with gcloud spanner instances list during setup.
When it happens
Trigger: Calling SpannerIO.read()/write() or the external ChangeStreamReader/ReadBuilder configuration without withInstanceId(...), or with instanceId("") — e.g. when the instance name is injected from a blank config value.
Common situations: Pipeline options where --spannerInstance was not passed on the command line; copy-pasted code where instanceId line was deleted; configs targeting Cloud Spanner emulator where the instance field was assumed optional.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- databaseId can't be empty
- Both clientCertPath and clientCertKeyPath must be specified
- Query and table params are mutually exclusive. Set just one
- Schema can't be empty
- ChangeStreamName can't be empty
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/098351f1f751426d.
Report an issue: GitHub.