{"record":{"id":"0842d94af72b8b4e","repo":"apache/beam","slug":"spannerio-read-requires-query-or-table-to-set-with-withtable","errorCode":null,"errorMessage":"SpannerIO.read() requires query OR table to set with withTable OR withQuery method.","messagePattern":"SpannerIO\\.read\\(\\) requires query OR table to set with withTable OR withQuery method\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerIO.java","lineNumber":1130,"sourceCode":"\n      if (getReadOperation().getQuery() != null) {\n        // TODO: validate query?\n        if (getReadOperation().getTable() != null) {\n          throw new IllegalArgumentException(\n              \"Both query and table cannot be specified at the same time for SpannerIO.read().\");\n        }\n      } else if (getReadOperation().getTable() != null) {\n        // Assume read\n        checkNotNull(\n            getReadOperation().getColumns(),\n            \"For a read operation SpannerIO.read() requires a list of \"\n                + \"columns to set with withColumns method\");\n        checkArgument(\n            !getReadOperation().getColumns().isEmpty(),\n            \"For a read operation SpannerIO.read() requires a non-empty\"\n                + \" list of columns to set with withColumns method\");\n      } else {\n        throw new IllegalArgumentException(\n            \"SpannerIO.read() requires query OR table to set with withTable OR withQuery method.\");\n      }\n\n      final SpannerSourceDef sourceDef = createSourceDef();\n\n      Schema beamSchema = null;\n      if (getTypeDescriptor() != null && getToBeamRowFn() != null && getFromBeamRowFn() != null) {\n        beamSchema = sourceDef.getBeamSchema();\n      }\n\n      ReadAll readAll =\n          readAll()\n              .withSpannerConfig(getSpannerConfig())\n              .withTimestampBound(getTimestampBound())\n              .withBatching(getBatching())\n              .withTransaction(getTransaction());\n\n      PCollection<Struct> rows =","sourceCodeStart":1112,"sourceCodeEnd":1148,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerIO.java#L1112-L1148","documentation":"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).","triggerScenarios":"Calling SpannerIO.read() and expanding it into a pipeline without ever calling .withQuery(...) or .withTable(...) (or with an empty ReadOperation).","commonSituations":"Incomplete builder chains when generating reads dynamically; conditionally setting query/table but neither branch executing; refactoring that dropped the withTable call.","solutions":["Add .withTable(name).withColumns(...) or .withQuery(sql) to the SpannerIO.read() builder","Verify the code path that sets the source actually executes (log the ReadOperation before apply)","Check that config values feeding table/query are not null/empty"],"exampleFix":"// before\nSpannerIO.read().withSpannerConfig(config).applyTo(...)\n// after\nSpannerIO.read().withSpannerConfig(config).withTable(\"users\").withColumns(\"id\",\"name\")","handlingStrategy":"validation","validationCode":"if (query == null && table == null) { throw new IllegalArgumentException(\"SpannerIO.read() needs withQuery or withTable\"); }","typeGuard":null,"tryCatchPattern":"try { pipeline.apply(spannerRead); } catch (IllegalArgumentException e) { LOG.error(\"Configure query or table: {}\", e.getMessage()); }","preventionTips":["Always chain .withTable(...).withColumns(...) or .withQuery(...)","Assert ReadOperation completeness in unit tests before apply","Guard dynamic config so empty strings are treated as unset"],"tags":["java","spanner","builder","missing-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}