apache/beam · error · IllegalArgumentException

SpannerIO.read() requires query OR table to set with…

Error message

SpannerIO.read() requires query OR table to set with withTable OR withQuery method.

What it means

SpannerIO.read() requires a data source: either a SQL query (withQuery) or a table (withTable). When a Read operation has neither set, validation throws IllegalArgumentException at pipeline construction. If a table is given, non-empty columns must also be set (unless a query is used).

Solutions

  1. Add .withTable(name).withColumns(...) or .withQuery(sql) to the SpannerIO.read() builder
  2. Verify the code path that sets the source actually executes (log the ReadOperation before apply)
  3. Check that config values feeding table/query are not null/empty

Example fix

// before
SpannerIO.read().withSpannerConfig(config).applyTo(...)
// after
SpannerIO.read().withSpannerConfig(config).withTable("users").withColumns("id","name")
Defensive patterns

Strategy: validation

Validate before calling

if (query == null && table == null) { throw new IllegalArgumentException("SpannerIO.read() needs withQuery or withTable"); }

Try / catch

try { pipeline.apply(spannerRead); } catch (IllegalArgumentException e) { LOG.error("Configure query or table: {}", e.getMessage()); }

Prevention

When it happens

Trigger: Calling SpannerIO.read() and expanding it into a pipeline without ever calling .withQuery(...) or .withTable(...) (or with an empty ReadOperation).

Common situations: Incomplete builder chains when generating reads dynamically; conditionally setting query/table but neither branch executing; refactoring that dropped the withTable call.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerIO.java:1130

      if (getReadOperation().getQuery() != null) {
        // TODO: validate query?
        if (getReadOperation().getTable() != null) {
          throw new IllegalArgumentException(
              "Both query and table cannot be specified at the same time for SpannerIO.read().");
        }
      } else if (getReadOperation().getTable() != null) {
        // Assume read
        checkNotNull(
            getReadOperation().getColumns(),
            "For a read operation SpannerIO.read() requires a list of "
                + "columns to set with withColumns method");
        checkArgument(
            !getReadOperation().getColumns().isEmpty(),
            "For a read operation SpannerIO.read() requires a non-empty"
                + " list of columns to set with withColumns method");
      } else {
        throw new IllegalArgumentException(
            "SpannerIO.read() requires query OR table to set with withTable OR withQuery method.");
      }

      final SpannerSourceDef sourceDef = createSourceDef();

      Schema beamSchema = null;
      if (getTypeDescriptor() != null && getToBeamRowFn() != null && getFromBeamRowFn() != null) {
        beamSchema = sourceDef.getBeamSchema();
      }

      ReadAll readAll =
          readAll()
              .withSpannerConfig(getSpannerConfig())
              .withTimestampBound(getTimestampBound())
              .withBatching(getBatching())
              .withTransaction(getTransaction());

      PCollection<Struct> rows =

View on GitHub (pinned to 12126d8942)