{"record":{"id":"e1e6c467dc8e7148","repo":"apache/beam","slug":"readoperation-is-improperly-configure-s","errorCode":null,"errorMessage":"ReadOperation is improperly configure: %s","messagePattern":"ReadOperation is improperly configure: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/gcp/experimental/spannerio.py","lineNumber":428,"sourceCode":"    # side input\n    self._snapshot = BatchSnapshot.from_dict(self._database, transaction_info)\n\n    # getting the transaction from the snapshot's session to run read operation.\n    # with self._snapshot.session().transaction() as transaction:\n    with self._get_session().transaction() as transaction:\n      table_id = self._spanner_configuration.table\n      query_name = self._spanner_configuration.query_name or ''\n\n      if element.is_sql is True:\n        transaction_read = transaction.execute_sql\n        metric_action = self._query_metric\n        metric_id = query_name\n      elif element.is_table is True:\n        transaction_read = transaction.read\n        metric_action = self._table_metric\n        metric_id = table_id\n      else:\n        raise ValueError(\n            \"ReadOperation is improperly configure: %s\" % str(element))\n\n      try:\n        for row in transaction_read(**element.kwargs):\n          yield row\n\n        metric_action(metric_id, 'ok')\n      except (ClientError, GoogleAPICallError) as e:\n        metric_action(metric_id, e.code.value)\n        raise\n\n\n@with_input_types(ReadOperation)\n@with_output_types(dict[typing.Any, typing.Any])\nclass _CreateReadPartitions(DoFn):\n  \"\"\"\n  A DoFn to create partitions. Uses the Partitioning API (PartitionRead /\n  PartitionQuery) request to start a partitioned query operation. Returns a","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/gcp/experimental/spannerio.py#L410-L446","documentation":"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.","triggerScenarios":"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.","commonSituations":"Building a custom read DoFn and instantiating ReadOperation directly instead of the factories; an element silently defaulting through pickling or Beam Fn wiring.","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."],"exampleFix":"// before\nop = ReadOperation(kwargs={'table': 'Users'})\n// after\nop = ReadOperation.table(table='Users', columns=['id', 'name'])","handlingStrategy":"validation","validationCode":"def valid_read_op(op):\n    return bool(getattr(op, 'is_sql', False) or getattr(op, 'is_table', False))","typeGuard":null,"tryCatchPattern":"try:\n    rows = pc | ReadRows(config)\nexcept ValueError as e:\n    if 'ReadOperation is improperly configure' in str(e):\n        raise RuntimeError('Build ReadOperations via query()/table() factories') from e\n    raise","preventionTips":["Never instantiate ReadOperation directly; use query()/table() factories","Preserve flags through pickling/cross-language boundaries","Unit-test element construction before wiring into DoFns"],"tags":["google-cloud-spanner","state-error","apache-beam"],"backgroundTag":"invalid-state-transition","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"}