apache/beam · error · ValueError

keyset must be an instance of class…

Error message

keyset must be an instance of class google.cloud.spanner.KeySet

What it means

SpannerIO.ReadOperation.table() builds a Spanner 'read' operation and requires its keyset parameter to be a google.cloud.spanner.KeySet. Any other value (a dict of keys, a list, a string) is rejected with ValueError so malformed read specs fail fast instead of deep inside the Spanner client.

Solutions

  1. Wrap the keys in KeySet: from google.cloud.spanner import KeySet; KeySet(keys=[[1], [2]]) or KeySet(all_=True) to read everything.
  2. Omit keyset entirely to get the default KeySet(all_=True).
  3. Verify the KeySet import matches the google-cloud-spanner version pinned in requirements so isinstance passes.

Example fix

// before
op = ReadOperation.table(table='Users', columns=['id'], keyset=[[1],[2]])
// after
from google.cloud.spanner import KeySet
op = ReadOperation.table(table='Users', columns=['id'], keyset=KeySet(keys=[[1],[2]]))
Defensive patterns

Strategy: type-guard

Validate before calling

from google.cloud.spanner import KeySet
if keyset is not None and not isinstance(keyset, KeySet):
    keyset = KeySet(keys=keyset)  # coerce lists of keys

Type guard

def is_valid_keyset(keyset):
    from google.cloud.spanner import KeySet
    return keyset is None or isinstance(keyset, KeySet)

Try / catch

try:
    op = ReadOperation.table(table=t, columns=cols, keyset=ks)
except ValueError as e:
    logging.error('Bad keyset %r: %s', ks, e)
    op = ReadOperation.table(table=t, columns=cols, keyset=KeySet(all_=True))

Prevention

When it happens

Trigger: Calling ReadOperation.table(table='Users', columns=[...], keyset=...) with keyset given as a plain list of keys, a dict, or a KeySet imported from the wrong package (e.g. google.cloud.spanner_v1 vs the expected spanner KeySet class).

Common situations: Developers hand-rolling reads assume keyset accepts key lists; mixing google-cloud-spanner versions so isinstance() fails against a differently-shipped KeySet class.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at sdks/python/apache_beam/io/gcp/experimental/spannerio.py:286

            'sql': sql, 'params': params, 'param_types': param_types
        })

  @classmethod
  def table(cls, table, columns, index="", keyset=None):
    """
    A convenient method to construct ReadOperation from table.

    Args:
      table: name of the table from which to fetch data.
      columns: names of columns to be retrieved.
      index: (optional) name of index to use, rather than the table's primary
        key.
      keyset: (optional) `KeySet` keys / ranges identifying rows to be
        retrieved.
    """
    keyset = keyset or KeySet(all_=True)
    if not isinstance(keyset, KeySet):
      raise ValueError(
          "keyset must be an instance of class "
          "google.cloud.spanner.KeySet")
    return cls(
        is_sql=False,
        is_table=True,
        read_operation="process_read_batch",
        kwargs={
            'table': table,
            'columns': columns,
            'index': index,
            'keyset': keyset
        })


class _BeamSpannerConfiguration(namedtuple("_BeamSpannerConfiguration",
                                           ["project",
                                            "instance",
                                            "database",

View on GitHub (pinned to 12126d8942)