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

  1. Add .withInstanceId("<your-instance>") to the Spanner builder.
  2. If derived from options, default it correctly or fail with a clear message before building the transform.
  3. 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

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


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/098351f1f751426d. Report an issue: GitHub.