{"record":{"id":"68c7cbafc23afe57","repo":"apache/beam","slug":"keyset-must-be-an-instance-of-class-google-cloud-spanner","errorCode":null,"errorMessage":"keyset must be an instance of class google.cloud.spanner.KeySet","messagePattern":"keyset must be an instance of class google\\.cloud\\.spanner\\.KeySet","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/gcp/experimental/spannerio.py","lineNumber":286,"sourceCode":"            'sql': sql, 'params': params, 'param_types': param_types\n        })\n\n  @classmethod\n  def table(cls, table, columns, index=\"\", keyset=None):\n    \"\"\"\n    A convenient method to construct ReadOperation from table.\n\n    Args:\n      table: name of the table from which to fetch data.\n      columns: names of columns to be retrieved.\n      index: (optional) name of index to use, rather than the table's primary\n        key.\n      keyset: (optional) `KeySet` keys / ranges identifying rows to be\n        retrieved.\n    \"\"\"\n    keyset = keyset or KeySet(all_=True)\n    if not isinstance(keyset, KeySet):\n      raise ValueError(\n          \"keyset must be an instance of class \"\n          \"google.cloud.spanner.KeySet\")\n    return cls(\n        is_sql=False,\n        is_table=True,\n        read_operation=\"process_read_batch\",\n        kwargs={\n            'table': table,\n            'columns': columns,\n            'index': index,\n            'keyset': keyset\n        })\n\n\nclass _BeamSpannerConfiguration(namedtuple(\"_BeamSpannerConfiguration\",\n                                           [\"project\",\n                                            \"instance\",\n                                            \"database\",","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/gcp/experimental/spannerio.py#L268-L304","documentation":"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.","triggerScenarios":"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).","commonSituations":"Developers hand-rolling reads assume keyset accepts key lists; mixing google-cloud-spanner versions so isinstance() fails against a differently-shipped KeySet class.","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."],"exampleFix":"// before\nop = ReadOperation.table(table='Users', columns=['id'], keyset=[[1],[2]])\n// after\nfrom google.cloud.spanner import KeySet\nop = ReadOperation.table(table='Users', columns=['id'], keyset=KeySet(keys=[[1],[2]]))","handlingStrategy":"type-guard","validationCode":"from google.cloud.spanner import KeySet\nif keyset is not None and not isinstance(keyset, KeySet):\n    keyset = KeySet(keys=keyset)  # coerce lists of keys","typeGuard":"def is_valid_keyset(keyset):\n    from google.cloud.spanner import KeySet\n    return keyset is None or isinstance(keyset, KeySet)","tryCatchPattern":"try:\n    op = ReadOperation.table(table=t, columns=cols, keyset=ks)\nexcept ValueError as e:\n    logging.error('Bad keyset %r: %s', ks, e)\n    op = ReadOperation.table(table=t, columns=cols, keyset=KeySet(all_=True))","preventionTips":["Always wrap keys in KeySet(keys=[...])","Omit keyset to read all rows","Pin google-cloud-spanner version so isinstance checks match"],"tags":["google-cloud-spanner","type-check","apache-beam"],"backgroundTag":"type-mismatch","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"}