apache/beam · error · ValueError
ReadOperation is improperly configure
Error message
ReadOperation is improperly configure: %s
What it means
The ReadOperation element reaching this DoFn's process() has neither is_sql nor is_table set to True, so Beam cannot pick a transaction read action (query vs table read). It raises ValueError naming the offending element. Such an element can only come from a misconstructed ReadOperation.
Solutions
- Create read operations only via ReadOperation.query(sql=...) or ReadOperation.table(table=..., columns=...).
- Log/print the element to see why is_sql and is_table are falsy and fix the construction site.
- If building a custom transform, set is_sql=True or is_table=True on the ReadOperation explicitly.
Example fix
// before
op = ReadOperation(kwargs={'table': 'Users'})
// after
op = ReadOperation.table(table='Users', columns=['id', 'name']) Defensive patterns
Strategy: validation
Validate before calling
def valid_read_op(op):
return bool(getattr(op, 'is_sql', False) or getattr(op, 'is_table', False)) Try / catch
try:
rows = pc | ReadRows(config)
except ValueError as e:
if 'ReadOperation is improperly configure' in str(e):
raise RuntimeError('Build ReadOperations via query()/table() factories') from e
raise Prevention
- Never instantiate ReadOperation directly; use query()/table() factories
- Preserve flags through pickling/cross-language boundaries
- Unit-test element construction before wiring into DoFns
When it happens
Trigger: Constructing ReadOperation without using the ReadOperation.query() or ReadOperation.table() factory methods (e.g. ReadOperation() directly, leaving is_sql/is_table as None/False), or deserializing/corrupting a ReadOperation in a cross-language pipeline.
Common situations: Building a custom read DoFn and instantiating ReadOperation directly instead of the factories; an element silently defaulting through pickling or Beam Fn wiring.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Both clientCertPath and clientCertKeyPath must be specified…
- ChangeStreamName can't be empty
- Columns are required with the table name.
- databaseId can't be empty
- instanceId can't be empty
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/e1e6c467dc8e7148.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/io/gcp/experimental/spannerio.py:428
# side input
self._snapshot = BatchSnapshot.from_dict(self._database, transaction_info)
# getting the transaction from the snapshot's session to run read operation.
# with self._snapshot.session().transaction() as transaction:
with self._get_session().transaction() as transaction:
table_id = self._spanner_configuration.table
query_name = self._spanner_configuration.query_name or ''
if element.is_sql is True:
transaction_read = transaction.execute_sql
metric_action = self._query_metric
metric_id = query_name
elif element.is_table is True:
transaction_read = transaction.read
metric_action = self._table_metric
metric_id = table_id
else:
raise ValueError(
"ReadOperation is improperly configure: %s" % str(element))
try:
for row in transaction_read(**element.kwargs):
yield row
metric_action(metric_id, 'ok')
except (ClientError, GoogleAPICallError) as e:
metric_action(metric_id, e.code.value)
raise
@with_input_types(ReadOperation)
@with_output_types(dict[typing.Any, typing.Any])
class _CreateReadPartitions(DoFn):
"""
A DoFn to create partitions. Uses the Partitioning API (PartitionRead /
PartitionQuery) request to start a partitioned query operation. Returns aView on GitHub (pinned to 12126d8942)