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
- Wrap the keys in KeySet: from google.cloud.spanner import KeySet; KeySet(keys=[[1], [2]]) or KeySet(all_=True) to read everything.
- Omit keyset entirely to get the default KeySet(all_=True).
- 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
- Always wrap keys in KeySet(keys=[...])
- Omit keyset to read all rows
- Pin google-cloud-spanner version so isinstance checks match
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
- Batch does not have expected dtype
- Batch does not have expected shape
- Batch is not an instance of ndarray
- Batch is not an instance of torch.Tensor
- Both clientCertPath and clientCertKeyPath must be specified…
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)